pcaprub 0.11.3 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.travis.yml +11 -0
- data/Gemfile +20 -0
- data/README.rdoc +57 -13
- data/Rakefile +71 -49
- data/ext/{pcaprub → pcaprub_c}/extconf.rb +20 -26
- data/ext/{pcaprub → pcaprub_c}/pcaprub.c +405 -139
- data/lib/pcaprub/ext.rb +15 -1
- data/lib/pcaprub/version.rb +7 -7
- data/test/helper.rb +8 -1
- data/test/test_pcaprub_unit.rb +111 -89
- metadata +106 -19
- data/pcaprub.gemspec +0 -60
checksums.yaml
ADDED
@@ -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=
|
data/.travis.yml
ADDED
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'
|
data/README.rdoc
CHANGED
@@ -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.
|
5
|
-
|
6
|
-
|
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
|
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 @
|
30
|
-
git clone git://github.com/
|
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
|
-
|
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
|
-
|
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
|
-
===
|
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
|
2
|
-
require '
|
3
|
-
require 'rake/clean'
|
4
|
-
require './lib/pcaprub/version'
|
1
|
+
#require "bundler/gem_tasks"
|
2
|
+
require './lib/pcaprub/version.rb'
|
5
3
|
|
6
|
-
|
7
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
86
|
+
task :test
|
76
87
|
|
77
|
-
|
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 = '
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
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
|
-
|
35
|
+
have_library("wpcap", "pcap_setnonblock")
|
34
36
|
else
|
35
|
-
have_library("pcap", "pcap_open_live")
|
36
|
-
|
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
|
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
|
-
|
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, "
|
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 =
|
639
|
-
rbpacket->pkt = (u_char *)
|
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
|
-
|
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
|
-
|
663
|
-
|
664
|
-
#if
|
665
|
-
fno =
|
872
|
+
if(! rbpcap_ready(rbp)) return self;
|
873
|
+
|
874
|
+
#if defined(WIN32)
|
875
|
+
fno = (int)pcap_getevent(rbp->pd);
|
666
876
|
#else
|
667
|
-
fno =
|
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
|
-
|
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
|
-
|
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 =
|
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
|
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
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|
}
|