pcaprub 0.11.3 → 0.12.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.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTM1M2U0NmViOTRlNDVkNDk3ZWU5Yzk5NDI4OTk5MmQ0ZDE5ZWJlMg==
5
+ data.tar.gz: !binary |-
6
+ MzcyNDk3YTY1YjUzNGE2ZDQyYTQ1MTU4YTk3YjcyOGY3NGIxODIxMg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ OGYwOWYxMTM1Y2VjOTE0NzBlOTA1NTljMzJkNmFlZWEyOWQ2MTI2MDE0ODVh
10
+ NDJkNjgxOTM3ODk4YzRhMjFlMDMwYTcxZjM3Mzk4OTJiNTI5ODhiOTU5NmVm
11
+ MTBhNGQxNTI0ZDMyNGJmMmRhNzJlYmUzNjZhZGEzNjFiYjAyMTA=
12
+ data.tar.gz: !binary |-
13
+ ODc3OGFhY2RjZmEwNzIzM2IwNGQ1OGNiMTQ5MzhmY2JiMDUyNDA5NDAxYTZm
14
+ MGJmZDJmNGVkNmM4YjY4MjMwZTYwODI2NTc3OGE4MTNmZDAyZTE3MGM3Y2Qy
15
+ YzBhNTcyYTMxOTZkZTQ4YmIzY2Y2ZWQyYmZkOWQ5Mjc1MWYxODE=
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ before_install:
3
+ - sudo apt-get install libpcap-dev -qq
4
+ rvm:
5
+ - 1.8.7
6
+ - 1.9.3
7
+ - 2.0.0
8
+ - 2.1.0
9
+ # - ruby-head
10
+ script:
11
+ - rvmsudo bundle exec rake
data/Gemfile ADDED
@@ -0,0 +1,20 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # No more static spec file
4
+
5
+ platforms :ruby_18 do
6
+ gem 'rdoc'
7
+ end
8
+
9
+ group :development, :test do
10
+ # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
11
+ gem 'minitest', '~> 4.7.0'
12
+ gem 'shoulda-context', '~> 1.1.6'
13
+ platforms :ruby_19, :ruby_20, :ruby_21 do
14
+ gem 'coveralls', :require => false
15
+ end
16
+ end
17
+
18
+ gem 'rake', '>= 0.9.2'
19
+ gem 'rake-compiler', '>= 0.6.0'
20
+ gem 'rubygems-tasks'
@@ -1,18 +1,36 @@
1
1
  = pcaprub
2
2
 
3
+ {<img src="https://travis-ci.org/pcaprub/pcaprub.png" alt="Build Status" />}[https://travis-ci.org/pcaprub/pcaprub]
4
+ {<img src="https://codeclimate.com/github/pcaprub/pcaprub.png" />}[https://codeclimate.com/github/pcaprub/pcaprub]
5
+ {<img src="https://badge.fury.io/rb/pcaprub.png" alt="Gem Version" />}[http://badge.fury.io/rb/pcaprub]
6
+ {<img src="https://gemnasium.com/pcaprub/pcaprub.svg" alt="Dependency Status" />}[https://gemnasium.com/pcaprub/pcaprub]
7
+
3
8
  This goal of this project is to provide a consistent interface
4
- to LBL's libpcap packet capture library. This project was created
5
- because the currently available ruby-pcap library is poorly designed
6
- and has been unmaintained since 2000.
9
+ to LBL's libpcap packet capture library.
10
+
11
+ == Limitations
7
12
 
8
13
  This does not provide packet processing functionality, it simply provides
9
14
  the interface for capturing packets, and passing yielding those packets.
10
15
 
11
- For true packet processing capability look at PCAPFU PCAPLET etc..
16
+ For packet processing capability look at ruby gems PCAPFU, PCAPLET, etc..
17
+
18
+ == Requirements
19
+
20
+ MRI POSIX Ruby (Native compilation)
21
+ Ruby 1.8.7 (EOL June 2014)
22
+ Ruby 1.9.3 or higher
23
+ Ruby 2.x or higher
12
24
 
13
- Requirements:
14
25
  libpcap - http://www.tcpdump.org
15
26
 
27
+ MRI Windows Ruby (Native compilation)
28
+ Ruby 1.8.7 (EOL June 2014)
29
+ Ruby 1.9.3 or higher
30
+ Ruby 2.x or higher
31
+
32
+ WinPcap - http://www.winpcap.org
33
+
16
34
  == Installation
17
35
 
18
36
  gem install pcaprub
@@ -26,10 +44,12 @@ Requirements:
26
44
 
27
45
  == Current Repository for Gemcutter source
28
46
 
29
- The Git Repo on Github @shadowbq is forked from the Metasploit SVN repo
30
- git clone git://github.com/shadowbq/pcaprub.git
47
+ The Git Repo on Github @pcaprub is forked from the Metasploit SVN repo
48
+ git clone git://github.com/pcaprub/pcaprub.git
49
+
50
+ == Additionals
31
51
 
32
- == Notes on 11.x series and beyond.
52
+ === Notes on 0.11.x series and beyond.
33
53
 
34
54
  The gem is now a module. The module is autoincluded, but this helps with name collisions and additional growth.
35
55
 
@@ -42,7 +62,7 @@ The file handling in dumper is now attached to the Capture Class and not the Mod
42
62
  { ... }
43
63
  capture.dump_close
44
64
 
45
- == Timstamps from the PCAP Header
65
+ === Timstamps from the PCAP Header
46
66
 
47
67
  Timestamps are now available when yeilding packets instead of strings
48
68
 
@@ -52,7 +72,29 @@ Timestamps are now available when yeilding packets instead of strings
52
72
  puts "micro => #{packet.microsec}"
53
73
  end
54
74
 
55
- === Notes on other repositories
75
+ === Ruby 1.8.7 & WinPcap
76
+
77
+ On Ruby 1.8 with winpcap, rb_thread_polling pauses for 100 milliseconds between reads. This may mean some packets are missed.
78
+
79
+
80
+ == LICENSE
81
+
82
+ GNU Lesser General Public License v2.1 (LGPL-2.1)
83
+
84
+ https://www.tldrlegal.com/l/lgpl2
85
+
86
+ See LICENCE for details
87
+
88
+ Copyright © 2010 - 2014
89
+
90
+ === Notes on other repositories in compliance with LGPL-2.1
91
+
92
+ All original code maintains its copyright from its original authors and licensing.
93
+
94
+ On March 2014 this project was migrated to https://github.com/pcaprub/pcaprub from https://github.com/shadowbq/pcaprub
95
+
96
+ The Git Repo on Github @pcaprub is a forked merge from the Metasploit SVN repo
97
+ git clone git://github.com/shadowbq/pcaprub.git (moved)
56
98
 
57
99
  The Metasploit Project also provides a Subversion repository: (0.9-dev)
58
100
  svn checkout http://metasploit.com/svn/framework3/trunk/external/pcaprub/
@@ -60,14 +102,16 @@ The Metasploit Project also provides a Subversion repository: (0.9-dev)
60
102
  Packetfu Project also provides a listing (0.9-dev)
61
103
  http://code.google.com/p/packetfu/source/browse/#svn/trunk/pcaprub_linux
62
104
 
63
- The Outdate RubyForge svn version can be obtained from Subversion: (0.7-dev)
105
+ The Marshall Beddoe's Outdate RubyForge svn version can be obtained from Subversion: (0.7-dev)
64
106
  svn checkout http://pcaprub.rubyforge.org/svn/trunk/
65
107
  http download Public Rubyforge (0.6)
108
+ https://github.com/unmarshal/pcaprub
66
109
 
67
110
  SourceForge Masaki Fukushima 2000 (0.6) -- Object Creation Heavy Implementation (PCAPLET integrated)
68
111
  http://sourceforge.net/apps/trac/rubypcap/
69
112
 
70
113
  Additonal Github Repos
71
- github.com/dxoigmn/pcaprub (0.8-dev)
72
- github.com/spox /pcaprub-spox (0.8-dev+)
114
+ https://github.com/dxoigmn/pcaprub (0.8-dev)
115
+ https://github.com/spox /pcaprub-spox (0.8-dev+)
116
+
73
117
 
data/Rakefile CHANGED
@@ -1,56 +1,67 @@
1
- require 'rubygems'
2
- require 'rake'
3
- require 'rake/clean'
4
- require './lib/pcaprub/version'
1
+ #require "bundler/gem_tasks"
2
+ require './lib/pcaprub/version.rb'
5
3
 
6
- desc "Build the extension:"
7
- task :compile => %W[ext/pcaprub/Makefile ext/pcaprub/pcaprub.c]
4
+ def java?
5
+ /java/ === RUBY_PLATFORM
6
+ end
8
7
 
8
+ ENV['LANG'] = "en_US.UTF-8"
9
9
 
10
- file "ext/pcaprub/Makefile" => ["ext/pcaprub/extconf.rb"] do
11
- Dir.chdir("ext/pcaprub") do
12
- ruby "extconf.rb"
13
- sh "make"
14
- end
15
- cp "ext/pcaprub/pcaprub.so", "lib"
16
- end
17
10
 
18
- CLEAN.include 'ext/**/Makefile'
19
- CLEAN.include 'ext/**/*.o'
20
- CLEAN.include 'ext/**/mkmf.log'
21
- CLEAN.include 'ext/**/*.so'
22
- CLEAN.include 'lib/**/*.so'
11
+ @gemspec = Gem::Specification.new do |spec|
12
+ spec.name = "pcaprub"
13
+ spec.version = PCAPRUB::Pcap.version
14
+ spec.authors = ["shadowbq", "crondaemon", "jmcavinee", "unmarshal"]
15
+ spec.email = "shadowbq@gmail.com"
16
+ spec.description = "libpcap bindings for ruby with Ruby1.8, Ruby1.9, Ruby 2.x"
17
+ spec.summary = "libpcap bindings for ruby"
18
+ spec.homepage = "https://github.com/pcaprub/pcaprub"
19
+ spec.requirements = "libpcap"
20
+ spec.license = "LGPL-2.1"
23
21
 
24
- begin
25
- require 'jeweler'
26
- jeweler_tasks = Jeweler::Tasks.new do |gem|
27
- gem.name = "pcaprub"
28
- gem.summary = "libpcap bindings for ruby"
29
- gem.description = "libpcap bindings for ruby compat with JRUBY Ruby1.8 Ruby1.9"
30
- gem.email = "shadowbq@gmail.com"
31
- gem.homepage = "http://github.com/shadowbq/pcaprub"
32
- gem.authors = ["shadowbq"]
33
- gem.extensions = FileList['ext/**/extconf.rb']
34
- gem.rubyforge_project = 'pcaprub'
35
- gem.version = PCAPRUB::VERSION::STRING
36
- gem.files.include('lib/pcaprub.*') # add native stuff
37
- gem.extra_rdoc_files = FileList['README*', 'ChangeLog*', 'LICENSE*', 'FAQ*', 'USAGE*', 'ext/**/*.c']
38
- end
39
-
40
- $gemspec = jeweler_tasks.gemspec
41
- $gemspec.version = jeweler_tasks.jeweler.version
42
-
43
- Jeweler::GemcutterTasks.new
44
- rescue LoadError
45
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
46
- end
22
+ spec.files = [
23
+ ".document",
24
+ ".travis.yml",
25
+ "FAQ.rdoc",
26
+ "Gemfile",
27
+ "LICENSE",
28
+ "README.rdoc",
29
+ "Rakefile",
30
+ "USAGE.rdoc",
31
+ "examples/dead_cap.rb",
32
+ "examples/file_cap.rb",
33
+ "examples/simple_cap.rb",
34
+ "examples/telnet-raw.pcap",
35
+ "ext/pcaprub_c/extconf.rb",
36
+ "ext/pcaprub_c/pcaprub.c",
37
+ "lib/pcaprub.rb",
38
+ "lib/pcaprub/common.rb",
39
+ "lib/pcaprub/ext.rb",
40
+ "lib/pcaprub/version.rb",
41
+ "test/helper.rb",
42
+ "test/test_pcaprub.rb",
43
+ "test/test_pcaprub_unit.rb"
44
+ ]
47
45
 
48
- require "rubygems/package_task"
49
- Gem::PackageTask.new($gemspec) do |package|
50
- package.need_zip = false
51
- package.need_tar = false
52
- end
46
+ spec.extra_rdoc_files = [
47
+ "FAQ.rdoc",
48
+ "LICENSE",
49
+ "README.rdoc",
50
+ "USAGE.rdoc",
51
+ "ext/pcaprub_c/pcaprub.c"
52
+ ]
53
+ spec.extensions = FileList["ext/**/extconf.rb"]
54
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
55
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
56
+ spec.require_paths = ["lib"]
57
+
58
+ spec.add_development_dependency "bundler", "~> 1.3"
59
+ spec.add_development_dependency "rake", '>= 0.9.2'
60
+ spec.add_development_dependency "rake-compiler", '>= 0.6.0'
61
+ spec.add_development_dependency "shoulda-context", '~> 1.1.6'
62
+ spec.add_development_dependency "minitest", '~> 4.7.0'
53
63
 
64
+ end
54
65
 
55
66
  require 'rake/testtask'
56
67
  Rake::TestTask.new(:test) do |test|
@@ -72,13 +83,21 @@ rescue LoadError
72
83
  end
73
84
  end
74
85
 
75
- task :test => :check_dependencies
86
+ task :test
76
87
 
77
- task :default => %w[clean compile test]
88
+ require 'rubygems/package_task'
89
+ Gem::PackageTask.new(@gemspec) do |pkg|
90
+ pkg.need_zip = false
91
+ pkg.need_tar = false
92
+ end
93
+
94
+ require 'rake/extensiontask'
95
+ Rake::ExtensionTask.new('pcaprub_c', @gemspec)
96
+
97
+ task :default => [:compile, :test]
78
98
 
79
99
  require 'rdoc/task'
80
100
  RDoc::Task.new do |rdoc|
81
-
82
101
  version = PCAPRUB::VERSION::STRING
83
102
  rdoc.rdoc_dir = 'rdoc'
84
103
  rdoc.title = "pcaprub #{version}"
@@ -88,3 +107,6 @@ RDoc::Task.new do |rdoc|
88
107
  rdoc.rdoc_files.include('lib/**/*.rb')
89
108
  rdoc.rdoc_files.include('ext/**/*.c')
90
109
  end
110
+
111
+ require 'rubygems/tasks'
112
+ Gem::Tasks.new
@@ -1,27 +1,29 @@
1
1
  require 'mkmf'
2
- extension_name = 'pcaprub'
2
+ extension_name = 'pcaprub_c'
3
3
 
4
4
  puts "\n[*] Running checks for #{extension_name} code..."
5
5
  puts("platform is #{RUBY_PLATFORM}")
6
6
 
7
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")
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
19
  pcap_includedir = with_config("pcap-includedir", pcap_dir + "/include")
20
20
  pcap_libdir = with_config("pcap-libdir", pcap_dir + "/lib")
21
-
21
+ $CFLAGS = "-DWIN32 -I#{pcap_includedir}"
22
+ $LDFLAGS = "-L#{pcap_libdir}"
23
+
22
24
  have_library("wpcap", "pcap_open_live")
23
- have_library("wpcap", "pcap_setnonblock")
24
-
25
+ have_library("wpcap", "pcap_setnonblock")
26
+
25
27
  elsif /i386-mswin32/ =~ RUBY_PLATFORM
26
28
  pcap_dir = with_config("pcap-dir", "C:\\WpdPack")
27
29
  pcap_includedir = with_config("pcap-includedir", pcap_dir + "\\include")
@@ -30,18 +32,10 @@ elsif /i386-mswin32/ =~ RUBY_PLATFORM
30
32
  $CFLAGS = "-DWIN32 -I#{pcap_includedir}"
31
33
  $LDFLAGS = "/link /LIBPATH:#{pcap_libdir}"
32
34
  have_library("wpcap", "pcap_open_live")
33
- have_library("wpcap", "pcap_setnonblock")
35
+ have_library("wpcap", "pcap_setnonblock")
34
36
  else
35
- have_library("pcap", "pcap_open_live")
36
- have_library("pcap", "pcap_setnonblock")
37
+ have_library("pcap", "pcap_open_live", ["pcap.h"])
38
+ have_library("pcap", "pcap_setnonblock", ["pcap.h"])
37
39
  end
38
40
 
39
- if ( RUBY_VERSION =~ /^1\.8/ && !defined?(JRUBY_VERSION) )
40
- $CFLAGS += " -DMAKE_TRAP"
41
- end
42
-
43
-
44
- dir_config(extension_name)
45
41
  create_makefile(extension_name)
46
-
47
-
@@ -6,6 +6,9 @@
6
6
 
7
7
 
8
8
  #include <pcap.h>
9
+ #if defined(WIN32)
10
+ #include <Win32-Extensions.h>
11
+ #endif
9
12
 
10
13
  #if !defined(WIN32)
11
14
  #include <netinet/in.h>
@@ -17,6 +20,10 @@ static VALUE mPCAP;
17
20
  static VALUE rb_cPcap, rb_cPkt;
18
21
  static VALUE ePCAPRUBError, eDumperError, eBindingError, eBPFilterError;
19
22
 
23
+ #if defined(WIN32)
24
+ static VALUE rbpcap_thread_wait_handle(HANDLE fno);
25
+ #endif
26
+
20
27
  // Now defined in Native Ruby
21
28
  // #define PCAPRUB_VERSION "*.*.*"
22
29
 
@@ -25,8 +32,8 @@ static VALUE ePCAPRUBError, eDumperError, eBindingError, eBPFilterError;
25
32
 
26
33
  #if !defined(PCAP_NETMASK_UNKNOWN)
27
34
  /*
28
- * Version of libpcap < 1.1
29
- * Value to pass to pcap_compile() as the netmask if you dont know what the netmask is.
35
+ * Version of libpcap < 1.1
36
+ * Value to pass to pcap_compile() as the netmask if you dont know what the netmask is.
30
37
  */
31
38
  #define PCAP_NETMASK_UNKNOWN 0xffffffff
32
39
  #endif
@@ -46,7 +53,7 @@ typedef struct rbpcapjob {
46
53
  } rbpcapjob_t;
47
54
 
48
55
  typedef struct rbpacket {
49
- struct pcap_pkthdr* hdr;
56
+ struct pcap_pkthdr hdr;
50
57
  u_char* pkt;
51
58
  } rbpacket_t;
52
59
 
@@ -61,7 +68,7 @@ rbpcap_s_lookupdev(VALUE self)
61
68
  char *dev = NULL;
62
69
  char eb[PCAP_ERRBUF_SIZE];
63
70
  VALUE ret_dev; /* device string to return */
64
- #if defined(WIN32) /* pcap_lookupdev is broken on windows */
71
+ #if defined(WIN32) /* pcap_lookupdev is broken on windows */
65
72
  pcap_if_t *alldevs;
66
73
  pcap_if_t *d;
67
74
 
@@ -77,7 +84,7 @@ rbpcap_s_lookupdev(VALUE self)
77
84
  break;
78
85
  }
79
86
  }
80
-
87
+
81
88
  if (dev == NULL) {
82
89
  rb_raise(eBindingError,"%s","No valid interfaces found, Make sure WinPcap is installed.\n");
83
90
  }
@@ -104,7 +111,7 @@ rbpcap_s_lookupnet(VALUE self, VALUE dev)
104
111
  struct in_addr addr;
105
112
  char eb[PCAP_ERRBUF_SIZE];
106
113
  VALUE list;
107
-
114
+
108
115
  Check_Type(dev, T_STRING);
109
116
  if (pcap_lookupnet(StringValuePtr(dev), &net, &mask, eb) == -1) {
110
117
  rb_raise(rb_eRuntimeError, "%s", eb);
@@ -119,7 +126,7 @@ rbpcap_s_lookupnet(VALUE self, VALUE dev)
119
126
  }
120
127
 
121
128
  /*
122
- * Check if PCAP file or device is bound and loaded
129
+ * Check if PCAP file or device is bound and loaded
123
130
  */
124
131
  static int rbpcap_ready(rbpcap_t *rbp) {
125
132
  if(! rbp->pd) {
@@ -130,14 +137,13 @@ static int rbpcap_ready(rbpcap_t *rbp) {
130
137
  }
131
138
 
132
139
 
133
-
134
140
  /*
135
141
  * Automated Garbage Collection for Pcap Class
136
142
  */
137
143
  static void rbpcap_free(rbpcap_t *rbp) {
138
144
  if (rbp->pd)
139
145
  pcap_close(rbp->pd);
140
-
146
+
141
147
  if (rbp->pdt)
142
148
  pcap_dump_close(rbp->pdt);
143
149
 
@@ -151,15 +157,11 @@ static void rbpcap_free(rbpcap_t *rbp) {
151
157
  */
152
158
  static void rbpacket_free(rbpacket_t *rbpacket)
153
159
  {
154
-
155
- if(rbpacket->hdr != NULL) {
156
- rbpacket->hdr = NULL;
157
- }
158
-
160
+
159
161
  if(rbpacket->pkt != NULL) {
160
162
  rbpacket->pkt = NULL;
161
163
  }
162
-
164
+
163
165
  free(rbpacket);
164
166
  }
165
167
 
@@ -199,16 +201,129 @@ rbpacket_new_s(VALUE class)
199
201
  return self;
200
202
  }
201
203
 
204
+
205
+ /*
206
+ * call-seq:
207
+ * setmonitor(true)
208
+ *
209
+ * Set monitor mode for the capture.
210
+ *
211
+ * Returns the object itself.
212
+ */
213
+ static VALUE
214
+ rbpcap_setmonitor(VALUE self, VALUE mode)
215
+ {
216
+ rbpcap_t *rbp;
217
+ int rfmon_mode = 0;
218
+ Data_Get_Struct(self, rbpcap_t, rbp);
219
+ if (mode == Qtrue) {
220
+ rfmon_mode = 1;
221
+ } else if (mode == Qfalse) {
222
+ rfmon_mode = 0;
223
+ } else {
224
+ rb_raise(rb_eArgError, "Monitor mode must be a boolean");
225
+ }
226
+
227
+ #if defined(WIN32)
228
+ // monitor mode support was disabled in WinPcap 4.0.2
229
+ rb_raise(ePCAPRUBError, "set monitor mode not supported in WinPcap");
230
+ #else
231
+ if (pcap_set_rfmon(rbp->pd, rfmon_mode) == 0) {
232
+ return self;
233
+ } else {
234
+ rb_raise(ePCAPRUBError, "unable to set monitor mode");
235
+ }
236
+ #endif
237
+ }
238
+
239
+ /*
240
+ * call-seq:
241
+ * settimeout(1234)
242
+ *
243
+ * Set timeout for the capture.
244
+ *
245
+ * Returns the object itself.
246
+ */
247
+ static VALUE
248
+ rbpcap_settimeout(VALUE self, VALUE timeout)
249
+ {
250
+ rbpcap_t *rbp;
251
+ Data_Get_Struct(self, rbpcap_t, rbp);
252
+
253
+ if(TYPE(timeout) != T_FIXNUM)
254
+ rb_raise(rb_eArgError, "timeout must be a fixnum");
255
+
256
+ if (pcap_set_timeout(rbp->pd, NUM2INT(timeout)) == 0) {
257
+ return self;
258
+ } else {
259
+ rb_raise(ePCAPRUBError, "unable to set timeout");
260
+ }
261
+ }
262
+
263
+
264
+ /*
265
+ * call-seq:
266
+ * setsnaplen(true)
267
+ *
268
+ * Set snap length for the capture.
269
+ *
270
+ * Returns the object itself.
271
+ */
272
+ static VALUE
273
+ rbpcap_setsnaplen(VALUE self, VALUE snaplen)
274
+ {
275
+ rbpcap_t *rbp;
276
+ Data_Get_Struct(self, rbpcap_t, rbp);
277
+
278
+ if(TYPE(snaplen) != T_FIXNUM)
279
+ rb_raise(rb_eArgError, "snaplen must be a fixnum");
280
+
281
+ if (pcap_set_snaplen(rbp->pd, NUM2INT(snaplen)) == 0) {
282
+ return self;
283
+ } else {
284
+ rb_raise(ePCAPRUBError, "unable to set snap length");
285
+ }
286
+ }
287
+
288
+ /*
289
+ * call-seq:
290
+ * setpromisc(true)
291
+ *
292
+ * Set promiscuous mode for the capture.
293
+ *
294
+ * Returns the object itself.
295
+ */
296
+ static VALUE
297
+ rbpcap_setpromisc(VALUE self, VALUE mode)
298
+ {
299
+ rbpcap_t *rbp;
300
+ int promisc_mode = 0;
301
+ Data_Get_Struct(self, rbpcap_t, rbp);
302
+ if (mode == Qtrue) {
303
+ promisc_mode = 1;
304
+ } else if (mode == Qfalse) {
305
+ promisc_mode = 0;
306
+ } else {
307
+ rb_raise(rb_eArgError, "Promisc mode must be a boolean");
308
+ }
309
+
310
+ if (pcap_set_promisc(rbp->pd, promisc_mode) == 0) {
311
+ return self;
312
+ } else {
313
+ rb_raise(ePCAPRUBError, "unable to set promiscuous mode");
314
+ }
315
+ }
316
+
202
317
  /*
203
318
  * call-seq:
204
319
  * setfilter(filter)
205
320
  *
206
321
  * Provide a valid bpf-filter to apply to the packet capture
207
- *
322
+ *
208
323
  * # Show me all SYN packets:
209
324
  * bpf-filter = "tcp[13] & 2 != 0"
210
325
  * capture.setfilter(bpf-filter)
211
- *
326
+ *
212
327
  * Examples:
213
328
  * * "net 10.0.0.0/8"
214
329
  * * "not tcp and dst host 192.168.1.1"
@@ -228,8 +343,8 @@ rbpcap_setfilter(VALUE self, VALUE filter)
228
343
  if(TYPE(filter) != T_STRING)
229
344
  rb_raise(eBPFilterError, "filter must be a string");
230
345
 
231
- if(! rbpcap_ready(rbp)) return self;
232
-
346
+ if(! rbpcap_ready(rbp)) return self;
347
+
233
348
  if(rbp->type == LIVE)
234
349
  if(pcap_lookupnet(rbp->iface, &netid, &mask, eb) < 0) {
235
350
  netid = 0;
@@ -246,6 +361,93 @@ rbpcap_setfilter(VALUE self, VALUE filter)
246
361
  return self;
247
362
  }
248
363
 
364
+ /*
365
+ * Activate the interface
366
+ *
367
+ * call-seq:
368
+ * activate() -> self
369
+ *
370
+ * Returns the object itself.
371
+ */
372
+ static VALUE
373
+ rbpcap_activate(VALUE self)
374
+ {
375
+ rbpcap_t *rbp;
376
+ int errcode;
377
+ Data_Get_Struct(self, rbpcap_t, rbp);
378
+
379
+ if ((errcode = pcap_activate(rbp->pd)) == 0) {
380
+ return self;
381
+ } else {
382
+ rb_raise(ePCAPRUBError, "unable to activate interface: %d, %s", errcode, rbp->iface);
383
+ }
384
+ }
385
+
386
+
387
+ /*
388
+ * Close the interface
389
+ *
390
+ * call-seq:
391
+ * activate() -> self
392
+ *
393
+ * Returns the object itself.
394
+ */
395
+ static VALUE
396
+ rbpcap_close(VALUE self)
397
+ {
398
+ rbpcap_t *rbp;
399
+ Data_Get_Struct(self, rbpcap_t, rbp);
400
+
401
+ pcap_close(rbp->pd);
402
+ rbp->pd = NULL;
403
+ return self;
404
+ }
405
+
406
+ static VALUE
407
+ rbpcap_create(VALUE self, VALUE iface)
408
+ {
409
+ rbpcap_t *rbp;
410
+ char eb[PCAP_ERRBUF_SIZE];
411
+
412
+ Data_Get_Struct(self, rbpcap_t, rbp);
413
+
414
+ rbp->type = LIVE;
415
+ memset(rbp->iface, 0, sizeof(rbp->iface));
416
+ strncpy(rbp->iface, RSTRING_PTR(iface), sizeof(rbp->iface) - 1);
417
+
418
+ if(rbp->pd) {
419
+ pcap_close(rbp->pd);
420
+ }
421
+
422
+ rbp->pd = pcap_create(
423
+ RSTRING_PTR(iface),
424
+ eb
425
+ );
426
+
427
+ if(!rbp->pd)
428
+ rb_raise(rb_eRuntimeError, "%s", eb);
429
+
430
+ return self;
431
+ }
432
+
433
+ /*
434
+ *
435
+ * call-seq:
436
+ * create(iface) -> self
437
+ *
438
+ * capture = ::Pcap.create(@dev)
439
+ *
440
+ * Returns the object itself.
441
+ */
442
+ static VALUE
443
+ rbpcap_create_s(VALUE class, VALUE iface)
444
+ {
445
+ VALUE iPcap = rb_funcall(rb_cPcap, rb_intern("new"), 0);
446
+ return rbpcap_create(iPcap, iface);
447
+ }
448
+
449
+
450
+
249
451
  // transparent method
250
452
  static VALUE
251
453
  rbpcap_open_live(VALUE self, VALUE iface,VALUE snaplen,VALUE promisc, VALUE timeout)
@@ -281,7 +483,7 @@ rbpcap_open_live(VALUE self, VALUE iface,VALUE snaplen,VALUE promisc, VALUE time
281
483
 
282
484
 
283
485
  if(rbp->pd) {
284
- pcap_close(rbp->pd);
486
+ pcap_close(rbp->pd);
285
487
  }
286
488
 
287
489
  rbp->pd = pcap_open_live(
@@ -299,13 +501,13 @@ rbpcap_open_live(VALUE self, VALUE iface,VALUE snaplen,VALUE promisc, VALUE time
299
501
  }
300
502
 
301
503
  /*
302
- *
504
+ *
303
505
  * call-seq:
304
506
  * open_live(iface, snaplen, promisc, timeout) -> self
305
507
  *
306
508
  * capture = ::Pcap.open_live(@dev, @snaplength, @promiscous_mode, @timeout)
307
509
  *
308
- * Returns the object itself.
510
+ * Returns the object itself.
309
511
  */
310
512
  static VALUE
311
513
  rbpcap_open_live_s(VALUE class, VALUE iface, VALUE snaplen, VALUE promisc, VALUE timeout)
@@ -341,11 +543,11 @@ rbpcap_open_offline(VALUE self, VALUE filename)
341
543
  }
342
544
 
343
545
  /*
344
- *
546
+ *
345
547
  * call-seq:
346
548
  * open_offline(filename) -> self
347
549
  *
348
- * capture = ::Pcap.open_offline(filename)
550
+ * capture = ::Pcap.open_offline(filename)
349
551
  *
350
552
  * Returns the object itself.
351
553
  */
@@ -357,7 +559,7 @@ rbpcap_open_offline_s(VALUE class, VALUE filename)
357
559
  return rbpcap_open_offline(iPcap, filename);
358
560
  }
359
561
 
360
- // transparent method
562
+ // transparent method
361
563
  static VALUE
362
564
  rbpcap_open_dead(VALUE self, VALUE linktype, VALUE snaplen)
363
565
  {
@@ -384,7 +586,7 @@ rbpcap_open_dead(VALUE self, VALUE linktype, VALUE snaplen)
384
586
 
385
587
 
386
588
  /*
387
- *
589
+ *
388
590
  * call-seq:
389
591
  * open_dead(linktype, snaplen) -> self
390
592
  *
@@ -420,19 +622,19 @@ rbpcap_dump_open(VALUE self, VALUE filename)
420
622
 
421
623
  if(TYPE(filename) != T_STRING)
422
624
  rb_raise(rb_eArgError, "filename must be a string");
423
-
625
+
424
626
  Data_Get_Struct(self, rbpcap_t, rbp);
425
-
627
+
426
628
  if(! rbpcap_ready(rbp)) return self;
427
-
629
+
428
630
  rbp->pdt = pcap_dump_open(
429
631
  rbp->pd,
430
632
  RSTRING_PTR(filename)
431
633
  );
432
-
634
+
433
635
  if(!rbp->pdt)
434
636
  rb_raise(eDumperError, "Stream could not be initialized or opened.");
435
-
637
+
436
638
  return self;
437
639
  }
438
640
 
@@ -446,21 +648,21 @@ static VALUE
446
648
  rbpcap_dump_close(VALUE self)
447
649
  {
448
650
  rbpcap_t *rbp;
449
-
651
+
450
652
  Data_Get_Struct(self, rbpcap_t, rbp);
451
-
653
+
452
654
  if(! rbpcap_ready(rbp)) return self;
453
-
655
+
454
656
  if(!rbp->pdt)
455
657
  rb_raise(eDumperError, "Stream is already closed.");
456
-
658
+
457
659
  if (rbp->pdt)
458
660
  pcap_dump_close(rbp->pdt);
459
-
460
- rbp->pdt = NULL;
661
+
662
+ rbp->pdt = NULL;
461
663
 
462
664
  return self;
463
-
665
+
464
666
  }
465
667
 
466
668
 
@@ -488,17 +690,21 @@ rbpcap_dump(VALUE self, VALUE caplen, VALUE pktlen, VALUE packet)
488
690
  rb_raise(rb_eArgError, "pktlen must be a fixnum");
489
691
 
490
692
  Data_Get_Struct(self, rbpcap_t, rbp);
491
-
693
+
492
694
  gettimeofday(&pcap_hdr.ts, NULL);
493
695
  pcap_hdr.caplen = NUM2UINT(caplen);
494
696
  pcap_hdr.len = NUM2UINT(pktlen);
495
697
 
496
- //capture.next is yeilding an 8Bit ASCII string
698
+ if(!rbp->pdt) {
699
+ rb_raise(rb_eRuntimeError, "pcap_dumper not defined. You must open a dump file first");
700
+ }
701
+
702
+ //capture.next is yeilding an 8Bit ASCII string
497
703
  // -> return rb_str_new((char *) job.pkt, job.hdr.caplen);
498
704
  //Call dump such that capture.next{|pk| capture.dump(pk.length, pk.length, pk)}
499
705
 
500
- pcap_dump(
501
- (u_char*)rbp->pdt,
706
+ pcap_dump(
707
+ (u_char*)rbp->pdt,
502
708
  &pcap_hdr,
503
709
  (unsigned char *)RSTRING_PTR(packet)
504
710
  );
@@ -512,8 +718,8 @@ rbpcap_dump(VALUE self, VALUE caplen, VALUE pktlen, VALUE packet)
512
718
  * call-seq:
513
719
  * inject(payload)
514
720
  *
515
- * inject() transmit a raw packet through the network interface
516
- *
721
+ * inject() transmit a raw packet through the network interface
722
+ *
517
723
  * Returns the number of bytes written on success else raise failure.
518
724
  */
519
725
  static VALUE
@@ -522,13 +728,13 @@ rbpcap_inject(VALUE self, VALUE payload)
522
728
  rbpcap_t *rbp;
523
729
 
524
730
  if(TYPE(payload) != T_STRING)
525
- rb_raise(rb_eArgError, "payload must be a string");
731
+ rb_raise(rb_eArgError, "pupayload must be a string");
526
732
 
527
733
  Data_Get_Struct(self, rbpcap_t, rbp);
528
734
 
529
- if(! rbpcap_ready(rbp)) return self;
530
- #if defined(WIN32)
531
- /* WinPcap does not have a pcap_inject call we use pcap_sendpacket, if it suceedes
735
+ if(! rbpcap_ready(rbp)) return self;
736
+ #if defined(WIN32)
737
+ /* WinPcap does not have a pcap_inject call we use pcap_sendpacket, if it suceedes
532
738
  * we simply return the amount of packets request to inject, else we fail.
533
739
  */
534
740
  if(pcap_sendpacket(rbp->pd, RSTRING_PTR(payload), RSTRING_LEN(payload)) != 0) {
@@ -555,7 +761,7 @@ static void rbpcap_handler(rbpcapjob_t *job, struct pcap_pkthdr *hdr, u_char *pk
555
761
  /*
556
762
  **
557
763
  * Returns the next packet from the packet capture device.
558
- *
764
+ *
559
765
  * Returns a string with the packet data.
560
766
  *
561
767
  * If the next_data() is unsuccessful, Null is returned.
@@ -566,11 +772,11 @@ rbpcap_next_data(VALUE self)
566
772
  rbpcap_t *rbp;
567
773
  rbpcapjob_t job;
568
774
  char eb[PCAP_ERRBUF_SIZE];
569
- int ret;
570
-
775
+ int ret;
776
+
571
777
  Data_Get_Struct(self, rbpcap_t, rbp);
572
-
573
- if(! rbpcap_ready(rbp)) return self;
778
+
779
+ if(! rbpcap_ready(rbp)) return self;
574
780
  pcap_setnonblock(rbp->pd, 1, eb);
575
781
 
576
782
  #ifdef MAKE_TRAP
@@ -584,7 +790,7 @@ rbpcap_next_data(VALUE self)
584
790
  TRAP_END;
585
791
  #endif
586
792
 
587
- if(rbp->type == OFFLINE && ret <= 0)
793
+ if(rbp->type == OFFLINE && ret <= 0)
588
794
  return Qnil;
589
795
 
590
796
  if(ret > 0 && job.hdr.caplen > 0)
@@ -597,7 +803,7 @@ rbpcap_next_data(VALUE self)
597
803
  /*
598
804
  *
599
805
  * Returns the next packet from the packet capture device.
600
- *
806
+ *
601
807
  * Returns a string with the packet data.
602
808
  *
603
809
  * If the next_packet() is unsuccessful, Null is returned.
@@ -605,38 +811,38 @@ rbpcap_next_data(VALUE self)
605
811
 
606
812
  static VALUE
607
813
  rbpcap_next_packet(VALUE self)
608
- {
814
+ {
609
815
  rbpcap_t *rbp;
610
816
  rbpcapjob_t job;
611
817
  char eb[PCAP_ERRBUF_SIZE];
612
- int ret;
613
-
818
+ int ret;
819
+
614
820
  rbpacket_t* rbpacket;
615
-
821
+
616
822
  Data_Get_Struct(self, rbpcap_t, rbp);
617
-
618
- if(! rbpcap_ready(rbp)) return self;
823
+
824
+ if(! rbpcap_ready(rbp)) return self;
619
825
 
620
826
  pcap_setnonblock(rbp->pd, 1, eb);
621
827
 
622
828
  #ifdef MAKE_TRAP
623
829
  TRAP_BEG;
624
830
  #endif
625
-
831
+
626
832
  ret = pcap_dispatch(rbp->pd, 1, (pcap_handler) rbpcap_handler, (u_char *)&job);
627
833
 
628
834
  #ifdef MAKE_TRAP
629
835
  TRAP_END;
630
836
  #endif
631
837
 
632
- if(rbp->type == OFFLINE && ret <= 0)
838
+ if(rbp->type == OFFLINE && ret <= 0)
633
839
  return Qnil;
634
840
 
635
841
  if(ret > 0 && job.hdr.caplen > 0)
636
842
  {
637
843
  rbpacket = ALLOC(rbpacket_t);
638
- rbpacket->hdr = &job.hdr;
639
- rbpacket->pkt = (u_char *)&job.pkt;
844
+ rbpacket->hdr = job.hdr;
845
+ rbpacket->pkt = (u_char *)job.pkt;
640
846
  return Data_Wrap_Struct(rb_cPkt, 0, rbpacket_free, rbpacket);
641
847
  }
642
848
 
@@ -646,7 +852,7 @@ rbpcap_next_packet(VALUE self)
646
852
 
647
853
  /*
648
854
  * call-seq:
649
- * each_data() { |packet| ... }
855
+ * each_data() { |packet| ... }
650
856
  *
651
857
  * Yields each packet from the capture to the passed-in block in turn.
652
858
  *
@@ -655,22 +861,30 @@ static VALUE
655
861
  rbpcap_each_data(VALUE self)
656
862
  {
657
863
  rbpcap_t *rbp;
658
- int fno = -1;
659
-
864
+ #if defined(WIN32)
865
+ HANDLE fno;
866
+ #else
867
+ int fno = -1;
868
+ #endif
869
+
660
870
  Data_Get_Struct(self, rbpcap_t, rbp);
661
871
 
662
- if(! rbpcap_ready(rbp)) return self;
663
-
664
- #if !defined(WIN32)
665
- fno = pcap_get_selectable_fd(rbp->pd);
872
+ if(! rbpcap_ready(rbp)) return self;
873
+
874
+ #if defined(WIN32)
875
+ fno = (int)pcap_getevent(rbp->pd);
666
876
  #else
667
- fno = pcap_fileno(rbp->pd);
877
+ fno = pcap_get_selectable_fd(rbp->pd);
668
878
  #endif
669
879
 
670
880
  for(;;) {
671
881
  VALUE packet = rbpcap_next_data(self);
672
882
  if(packet == Qnil && rbp->type == OFFLINE) break;
883
+ #if defined(WIN32)
884
+ packet == Qnil ? rbpcap_thread_wait_handle(fno) : rb_yield(packet);
885
+ #else
673
886
  packet == Qnil ? rb_thread_wait_fd(fno) : rb_yield(packet);
887
+ #endif
674
888
  }
675
889
 
676
890
  return self;
@@ -679,7 +893,7 @@ rbpcap_each_data(VALUE self)
679
893
 
680
894
  /*
681
895
  * call-seq:
682
- * each_packet() { |packet| ... }
896
+ * each_packet() { |packet| ... }
683
897
  *
684
898
  * Yields a PCAP::Packet from the capture to the passed-in block in turn.
685
899
  *
@@ -688,22 +902,30 @@ static VALUE
688
902
  rbpcap_each_packet(VALUE self)
689
903
  {
690
904
  rbpcap_t *rbp;
691
- int fno = -1;
692
-
905
+
906
+ #if defined(WIN32)
907
+ HANDLE fno;
908
+ #else
909
+ int fno = -1;
910
+ #endif
911
+
693
912
  Data_Get_Struct(self, rbpcap_t, rbp);
913
+ if(! rbpcap_ready(rbp)) return self;
694
914
 
695
- if(! rbpcap_ready(rbp)) return self;
696
-
697
- #if !defined(WIN32)
698
- fno = pcap_get_selectable_fd(rbp->pd);
915
+ #if defined(WIN32)
916
+ fno = (int)pcap_getevent(rbp->pd);
699
917
  #else
700
- fno = pcap_fileno(rbp->pd);
918
+ fno = pcap_get_selectable_fd(rbp->pd);
701
919
  #endif
702
920
 
703
921
  for(;;) {
704
922
  VALUE packet = rbpcap_next_packet(self);
705
923
  if(packet == Qnil && rbp->type == OFFLINE) break;
924
+ #if defined(WIN32)
925
+ packet == Qnil ? rbpcap_thread_wait_handle(fno) : rb_yield(packet);
926
+ #else
706
927
  packet == Qnil ? rb_thread_wait_fd(fno) : rb_yield(packet);
928
+ #endif
707
929
  }
708
930
 
709
931
  return self;
@@ -714,8 +936,8 @@ rbpcap_each_packet(VALUE self)
714
936
  * call-seq:
715
937
  * datalink()
716
938
  *
717
- * Returns the integer datalink value unless capture
718
- *
939
+ * Returns the integer datalink value unless capture
940
+ *
719
941
  * foo.bar unless capture.datalink == Pcap::DLT_EN10MB
720
942
  */
721
943
  static VALUE
@@ -726,7 +948,7 @@ rbpcap_datalink(VALUE self)
726
948
  Data_Get_Struct(self, rbpcap_t, rbp);
727
949
 
728
950
  if(! rbpcap_ready(rbp)) return self;
729
-
951
+
730
952
  return INT2NUM(pcap_datalink(rbp->pd));
731
953
  }
732
954
 
@@ -734,8 +956,8 @@ rbpcap_datalink(VALUE self)
734
956
  * call-seq:
735
957
  * pcap_major_version()
736
958
  *
737
- * Returns the integer PCAP MAJOR LIBRARY value unless capture
738
- *
959
+ * Returns the integer PCAP MAJOR LIBRARY value unless capture
960
+ *
739
961
  */
740
962
  static VALUE
741
963
  rbpcap_major_version(VALUE self)
@@ -743,9 +965,9 @@ rbpcap_major_version(VALUE self)
743
965
  rbpcap_t *rbp;
744
966
 
745
967
  Data_Get_Struct(self, rbpcap_t, rbp);
746
-
968
+
747
969
  if(! rbpcap_ready(rbp)) return self;
748
-
970
+
749
971
  return INT2NUM(pcap_major_version(rbp->pd));
750
972
  }
751
973
 
@@ -753,8 +975,8 @@ rbpcap_major_version(VALUE self)
753
975
  * call-seq:
754
976
  * pcap_minor_version()
755
977
  *
756
- * Returns the integer PCAP MINOR LIBRARY value unless capture
757
- *
978
+ * Returns the integer PCAP MINOR LIBRARY value unless capture
979
+ *
758
980
  */
759
981
  static VALUE
760
982
  rbpcap_minor_version(VALUE self)
@@ -762,9 +984,9 @@ rbpcap_minor_version(VALUE self)
762
984
  rbpcap_t *rbp;
763
985
 
764
986
  Data_Get_Struct(self, rbpcap_t, rbp);
765
-
987
+
766
988
  if(! rbpcap_ready(rbp)) return self;
767
-
989
+
768
990
  return INT2NUM(pcap_minor_version(rbp->pd));
769
991
  }
770
992
 
@@ -773,7 +995,7 @@ rbpcap_minor_version(VALUE self)
773
995
  * snapshot()
774
996
  *
775
997
  * Returns the snapshot length, which is the number of bytes to save for each packet captured.
776
- *
998
+ *
777
999
  */
778
1000
  static VALUE
779
1001
  rbpcap_snapshot(VALUE self)
@@ -783,7 +1005,7 @@ rbpcap_snapshot(VALUE self)
783
1005
  Data_Get_Struct(self, rbpcap_t, rbp);
784
1006
 
785
1007
  if(! rbpcap_ready(rbp)) return self;
786
-
1008
+
787
1009
  return INT2NUM(pcap_snapshot(rbp->pd));
788
1010
  }
789
1011
 
@@ -794,9 +1016,9 @@ rbpcap_snapshot(VALUE self)
794
1016
  * Returns a hash with statistics of the packet capture
795
1017
  *
796
1018
  * - ["recv"] # number of packets received
797
- * - ["drop"] # number of packets dropped
1019
+ * - ["drop"] # number of packets dropped
798
1020
  * - ["idrop"] # number of packets dropped by interface
799
- *
1021
+ *
800
1022
  */
801
1023
  static VALUE
802
1024
  rbpcap_stats(VALUE self)
@@ -804,14 +1026,14 @@ rbpcap_stats(VALUE self)
804
1026
  rbpcap_t *rbp;
805
1027
  struct pcap_stat stat;
806
1028
  VALUE hash;
807
-
1029
+
808
1030
  Data_Get_Struct(self, rbpcap_t, rbp);
809
1031
 
810
1032
  if(! rbpcap_ready(rbp)) return self;
811
-
1033
+
812
1034
  if (pcap_stats(rbp->pd, &stat) == -1)
813
1035
  return Qnil;
814
-
1036
+
815
1037
  hash = rb_hash_new();
816
1038
  rb_hash_aset(hash, rb_str_new2("recv"), UINT2NUM(stat.ps_recv));
817
1039
  rb_hash_aset(hash, rb_str_new2("drop"), UINT2NUM(stat.ps_drop));
@@ -820,110 +1042,145 @@ rbpcap_stats(VALUE self)
820
1042
 
821
1043
  //#if defined(WIN32)
822
1044
  // rb_hash_aset(hash, rb_str_new2("bs_capt"), UINT2NUM(stat.bs_capt));
823
- //#endif
824
-
1045
+ //#endif
1046
+
825
1047
  return hash;
826
1048
  }
827
1049
 
828
1050
  /*
829
1051
  *
830
- * Returns the EPOCH integer from the ts.tv_sec record in the PCAP::Packet header
831
- *
1052
+ * Returns the EPOCH integer from the ts.tv_sec record in the PCAP::Packet header
1053
+ *
832
1054
  */
833
- static VALUE
1055
+ static VALUE
834
1056
  rbpacket_time(VALUE self)
835
1057
  {
836
1058
  rbpacket_t* rbpacket;
837
1059
  Data_Get_Struct(self, rbpacket_t, rbpacket);
838
- return INT2NUM(rbpacket->hdr->ts.tv_sec);
1060
+ return INT2NUM(rbpacket->hdr.ts.tv_sec);
839
1061
  }
840
1062
 
841
1063
  /*
842
1064
  *
843
- * Returns the tv_usec integer from the ts.tv_usec record in the PCAP::Packet header
844
- * timestamp microseconds
845
- * the microseconds when this packet was captured, as an offset to ts_sec.
846
- * Beware: this value shouldn't reach 1 second (1 000 000), in this case ts_sec must be increased instead!
1065
+ * Returns the tv_usec integer from the ts.tv_usec record in the PCAP::Packet header
1066
+ * timestamp microseconds
1067
+ * the microseconds when this packet was captured, as an offset to ts_sec.
1068
+ * Beware: this value shouldn't reach 1 second (1 000 000), in this case ts_sec must be increased instead!
847
1069
  *
848
1070
  * Ruby Microsecond Handling
849
1071
  * Time.at(946684800.2).usec #=> 200000
850
1072
  * Time.now.usec
851
1073
  */
852
1074
 
853
- static VALUE
1075
+ static VALUE
854
1076
  rbpacket_microsec(VALUE self)
855
1077
  {
856
1078
  rbpacket_t* rbpacket;
857
1079
  Data_Get_Struct(self, rbpacket_t, rbpacket);
858
- return INT2NUM(rbpacket->hdr->ts.tv_usec);
1080
+ return INT2NUM(rbpacket->hdr.ts.tv_usec);
859
1081
  }
860
1082
 
861
1083
 
862
1084
  /*
863
1085
  *
864
- * Returns the integer length of packet length field from the in the PCAP::Packet header
865
- *
1086
+ * Returns the integer length of packet length field from the in the PCAP::Packet header
1087
+ *
866
1088
  */
867
- static VALUE
1089
+ static VALUE
868
1090
  rbpacket_length(VALUE self)
869
1091
  {
870
1092
  rbpacket_t* rbpacket;
871
1093
  Data_Get_Struct(self, rbpacket_t, rbpacket);
872
- return INT2NUM(rbpacket->hdr->len);
1094
+ return INT2NUM(rbpacket->hdr.len);
873
1095
  }
874
1096
 
875
1097
  /*
876
1098
  *
877
- * Returns the integer length of capture len from the in the PCAP::Packet header
878
- *
1099
+ * Returns the integer length of capture len from the in the PCAP::Packet header
1100
+ *
879
1101
  */
880
- static VALUE
1102
+ static VALUE
881
1103
  rbpacket_caplen(VALUE self)
882
1104
  {
883
1105
  rbpacket_t* rbpacket;
884
1106
  Data_Get_Struct(self, rbpacket_t, rbpacket);
885
- return INT2NUM(rbpacket->hdr->caplen);
1107
+
1108
+ //test incorrect case
1109
+ if (rbpacket->hdr.caplen > rbpacket->hdr.len)
1110
+ return INT2NUM(rbpacket->hdr.len);
1111
+
1112
+ return INT2NUM(rbpacket->hdr.caplen);
886
1113
  }
887
1114
 
888
1115
  /*
889
1116
  *
890
- * Returns the integer PCAP MINOR LIBRARY value unless capture
891
- *
1117
+ * Returns the integer PCAP MINOR LIBRARY value unless capture
1118
+ *
892
1119
  */
893
- static VALUE
1120
+ static VALUE
894
1121
  rbpacket_data(VALUE self)
895
1122
  {
896
1123
  rbpacket_t* rbpacket;
897
1124
  Data_Get_Struct(self, rbpacket_t, rbpacket);
898
-
899
- if(rbpacket->pkt == NULL)
1125
+
1126
+ if ((rbpacket->pkt == NULL) || (rbpacket->hdr.caplen > rbpacket->hdr.len))
900
1127
  return Qnil;
901
-
902
- return rb_str_new((char *) rbpacket->pkt, rbpacket->hdr->caplen);
1128
+
1129
+ return rb_str_new((char *) rbpacket->pkt, rbpacket->hdr.caplen);
903
1130
  }
904
1131
 
1132
+ #if defined(WIN32)
1133
+ static VALUE
1134
+ rbpcap_thread_wait_handle_blocking(void *data)
1135
+ {
1136
+ VALUE result;
1137
+ result = (VALUE)WaitForSingleObject(data, 100);
1138
+ return result;
1139
+ }
1140
+
1141
+ /*
1142
+ *
1143
+ * Waits for the HANDLE returned by pcap_getevent to have data
1144
+ *
1145
+ */
1146
+ static VALUE
1147
+ rbpcap_thread_wait_handle(HANDLE fno)
1148
+ {
1149
+ VALUE result;
1150
+ #if MAKE_TRAP
1151
+ // Ruby 1.8 doesn't support rb_thread_blocking_region
1152
+ result = rb_thread_polling();
1153
+ #else
1154
+ result = (VALUE)rb_thread_blocking_region(
1155
+ rbpcap_thread_wait_handle_blocking,
1156
+ fno, RUBY_UBF_IO, 0);
1157
+ #endif
1158
+ return result;
1159
+ }
1160
+ #endif
1161
+
905
1162
 
906
1163
  void
907
- Init_pcaprub()
1164
+ Init_pcaprub_c()
908
1165
  {
909
1166
  /*
910
1167
  * Document-class: Pcap
911
- *
1168
+ *
912
1169
  * Main class defined by the pcaprub extension.
913
1170
  */
914
1171
  mPCAP = rb_define_module("PCAPRUB");
915
-
1172
+
916
1173
  rb_cPcap = rb_define_class_under(mPCAP,"Pcap", rb_cObject);
917
1174
  rb_cPkt = rb_define_class_under(mPCAP,"Packet", rb_cObject);
918
-
1175
+
919
1176
  ePCAPRUBError = rb_path2class("PCAPRUB::PCAPRUBError");
920
1177
  eBindingError = rb_path2class("PCAPRUB::BindingError");
921
1178
  eBPFilterError = rb_path2class("PCAPRUB::BPFError");
922
1179
  eDumperError = rb_path2class("PCAPRUB::DumperError");
923
-
924
- rb_define_module_function(rb_cPcap, "lookupdev", rbpcap_s_lookupdev, 0);
1180
+
1181
+ rb_define_module_function(rb_cPcap, "lookupdev", rbpcap_s_lookupdev, 0);
925
1182
  rb_define_module_function(rb_cPcap, "lookupnet", rbpcap_s_lookupnet, 1);
926
-
1183
+
927
1184
  rb_define_const(rb_cPcap, "DLT_NULL", INT2NUM(DLT_NULL));
928
1185
  rb_define_const(rb_cPcap, "DLT_EN10MB", INT2NUM(DLT_EN10MB));
929
1186
  rb_define_const(rb_cPcap, "DLT_EN3MB", INT2NUM(DLT_EN3MB));
@@ -945,7 +1202,7 @@ Init_pcaprub()
945
1202
  rb_define_const(rb_cPcap, "DLT_LINUX_SLL", INT2NUM(DLT_LINUX_SLL));
946
1203
  rb_define_const(rb_cPcap, "DLT_PRISM_HEADER", INT2NUM(DLT_PRISM_HEADER));
947
1204
  rb_define_const(rb_cPcap, "DLT_AIRONET_HEADER", INT2NUM(DLT_AIRONET_HEADER));
948
- /* Pcap Error Codes
1205
+ /* Pcap Error Codes
949
1206
  * Error codes for the pcap API.
950
1207
  * These will all be negative, so you can check for the success or
951
1208
  * failure of a call that returns these codes by checking for a
@@ -977,11 +1234,11 @@ Init_pcaprub()
977
1234
 
978
1235
 
979
1236
  rb_define_singleton_method(rb_cPcap, "new", rbpcap_new_s, 0);
980
-
1237
+ rb_define_singleton_method(rb_cPcap, "create", rbpcap_create_s, 1);
981
1238
  rb_define_singleton_method(rb_cPcap, "open_live", rbpcap_open_live_s, 4);
982
1239
  rb_define_singleton_method(rb_cPcap, "open_offline", rbpcap_open_offline_s, 1);
983
1240
  rb_define_singleton_method(rb_cPcap, "open_dead", rbpcap_open_dead_s, 2);
984
-
1241
+
985
1242
  rb_define_method(rb_cPcap, "dump_open", rbpcap_dump_open, 1);
986
1243
  rb_define_method(rb_cPcap, "dump_close", rbpcap_dump_close, 0);
987
1244
  rb_define_method(rb_cPcap, "dump", rbpcap_dump, 3);
@@ -989,6 +1246,7 @@ Init_pcaprub()
989
1246
  rb_define_method(rb_cPcap, "next_data", rbpcap_next_data, 0);
990
1247
  rb_define_method(rb_cPcap, "each_packet", rbpcap_each_packet, 0);
991
1248
  rb_define_method(rb_cPcap, "next_packet", rbpcap_next_packet, 0);
1249
+
992
1250
  /*
993
1251
  * Document-method: each
994
1252
  * Alias of each_data
@@ -998,22 +1256,30 @@ Init_pcaprub()
998
1256
  * Document-method: next
999
1257
  * Alias of next_data
1000
1258
  */
1259
+
1001
1260
  rb_define_method(rb_cPcap, "next", rbpcap_next_data, 0);
1002
1261
  rb_define_method(rb_cPcap, "setfilter", rbpcap_setfilter, 1);
1262
+ rb_define_method(rb_cPcap, "setmonitor", rbpcap_setmonitor, 1);
1263
+ rb_define_method(rb_cPcap, "setsnaplen", rbpcap_setsnaplen, 1);
1264
+ rb_define_method(rb_cPcap, "settimeout", rbpcap_settimeout, 1);
1265
+ rb_define_method(rb_cPcap, "setpromisc", rbpcap_setpromisc, 1);
1266
+ rb_define_method(rb_cPcap, "activate", rbpcap_activate, 0);
1003
1267
  rb_define_method(rb_cPcap, "inject", rbpcap_inject, 1);
1004
1268
  rb_define_method(rb_cPcap, "datalink", rbpcap_datalink, 0);
1005
1269
  rb_define_method(rb_cPcap, "pcap_major_version", rbpcap_major_version, 0);
1006
1270
  rb_define_method(rb_cPcap, "pcap_minor_version", rbpcap_minor_version, 0);
1007
1271
  rb_define_method(rb_cPcap, "snapshot", rbpcap_snapshot, 0);
1272
+ rb_define_method(rb_cPcap, "close", rbpcap_close, 0);
1273
+
1008
1274
  /*
1009
1275
  * Document-method: snaplen
1010
1276
  * Alias of snapshot
1011
1277
  */
1012
1278
  rb_define_method(rb_cPcap, "snaplen", rbpcap_snapshot, 0);
1013
1279
  rb_define_method(rb_cPcap, "stats", rbpcap_stats, 0);
1014
-
1280
+
1015
1281
  rb_define_singleton_method(rb_cPkt, "new", rbpacket_new_s, 0);
1016
-
1282
+
1017
1283
  rb_define_method(rb_cPkt, "time", rbpacket_time, 0);
1018
1284
  rb_define_method(rb_cPkt, "microsec", rbpacket_microsec, 0);
1019
1285
  rb_define_method(rb_cPkt, "length", rbpacket_length, 0);
@@ -1025,5 +1291,5 @@ Init_pcaprub()
1025
1291
  */
1026
1292
  rb_define_method(rb_cPkt, "to_s", rbpacket_data, 0);
1027
1293
 
1028
-
1294
+
1029
1295
  }