ffi-pcap 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/.pkg_ignore +25 -0
- data/.rspec +1 -0
- data/.specopts +1 -0
- data/.yardopts +1 -0
- data/{ChangeLog.rdoc → ChangeLog.md} +15 -5
- data/LICENSE.txt +1 -4
- data/README.md +92 -0
- data/Rakefile +30 -20
- data/examples/em_selectable_pcap.rb +38 -0
- data/examples/em_timer.rb +26 -0
- data/examples/ipfw_divert.rb +28 -8
- data/examples/print_bytes.rb +5 -1
- data/examples/replay.rb +11 -0
- data/examples/selectable_pcap.rb +29 -0
- data/ffi-pcap.gemspec +60 -0
- data/gemspec.yml +23 -0
- data/lib/ffi/pcap.rb +7 -13
- data/lib/ffi/pcap/addr.rb +16 -15
- data/lib/ffi/pcap/bpf_instruction.rb +25 -0
- data/lib/ffi/pcap/bpf_program.rb +85 -0
- data/lib/ffi/pcap/bsd.rb +9 -98
- data/lib/ffi/pcap/bsd/af.rb +18 -0
- data/lib/ffi/pcap/bsd/in6_addr.rb +16 -0
- data/lib/ffi/pcap/bsd/in_addr.rb +18 -0
- data/lib/ffi/pcap/bsd/sock_addr.rb +19 -0
- data/lib/ffi/pcap/bsd/sock_addr_dl.rb +24 -0
- data/lib/ffi/pcap/bsd/sock_addr_family.rb +19 -0
- data/lib/ffi/pcap/bsd/sock_addr_in.rb +21 -0
- data/lib/ffi/pcap/bsd/sock_addr_in6.rb +20 -0
- data/lib/ffi/pcap/bsd/typedefs.rb +7 -0
- data/lib/ffi/pcap/capture_wrapper.rb +296 -256
- data/lib/ffi/pcap/common_wrapper.rb +152 -127
- data/lib/ffi/pcap/copy_handler.rb +32 -32
- data/lib/ffi/pcap/crt.rb +7 -10
- data/lib/ffi/pcap/data_link.rb +178 -153
- data/lib/ffi/pcap/dead.rb +42 -29
- data/lib/ffi/pcap/dumper.rb +39 -41
- data/lib/ffi/pcap/error_buffer.rb +21 -36
- data/lib/ffi/pcap/exceptions.rb +21 -15
- data/lib/ffi/pcap/file_header.rb +24 -18
- data/lib/ffi/pcap/in_addr.rb +4 -4
- data/lib/ffi/pcap/interface.rb +22 -20
- data/lib/ffi/pcap/live.rb +296 -252
- data/lib/ffi/pcap/offline.rb +50 -43
- data/lib/ffi/pcap/packet.rb +186 -143
- data/lib/ffi/pcap/packet_header.rb +20 -18
- data/lib/ffi/pcap/pcap.rb +269 -212
- data/lib/ffi/pcap/stat.rb +19 -49
- data/lib/ffi/pcap/stat_ex.rb +42 -0
- data/lib/ffi/pcap/time_val.rb +52 -38
- data/lib/ffi/pcap/typedefs.rb +16 -20
- data/spec/data_link_spec.rb +39 -35
- data/spec/dead_spec.rb +0 -4
- data/spec/error_buffer_spec.rb +7 -9
- data/spec/file_header_spec.rb +17 -14
- data/spec/live_spec.rb +12 -5
- data/spec/offline_spec.rb +10 -11
- data/spec/packet_behaviors.rb +20 -6
- data/spec/packet_injection_spec.rb +9 -8
- data/spec/packet_spec.rb +22 -26
- data/spec/pcap_spec.rb +52 -40
- data/spec/spec_helper.rb +16 -5
- data/spec/wrapper_behaviors.rb +0 -3
- data/tasks/doc.rake +69 -0
- data/tasks/gem.rake +200 -0
- data/tasks/git.rake +40 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +286 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- metadata +142 -92
- data/README.rdoc +0 -30
- data/VERSION +0 -1
- data/lib/ffi/pcap/bpf.rb +0 -106
- data/lib/ffi/pcap/version.rb +0 -6
- data/tasks/rcov.rb +0 -6
- data/tasks/rdoc.rb +0 -17
- data/tasks/spec.rb +0 -9
- data/tasks/yard.rb +0 -21
data/gemspec.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
name: ffi-pcap
|
2
|
+
version: 0.2.1
|
3
|
+
summary: FFI bindings for libpcap
|
4
|
+
description: Bindings to libpcap via FFI interface in Ruby.
|
5
|
+
license: MIT
|
6
|
+
authors:
|
7
|
+
- Postmodern
|
8
|
+
- Dakrone
|
9
|
+
- Eric Monti
|
10
|
+
email: postmodern.mod3@gmail.com
|
11
|
+
homepage: https://github.com/sophsec/ffi-pcap
|
12
|
+
has_yard: true
|
13
|
+
|
14
|
+
requirements: libpcap >= 1.0.0
|
15
|
+
|
16
|
+
dependencies:
|
17
|
+
ffi: ~> 1.0
|
18
|
+
ffi_dry: ~> 0.1.12
|
19
|
+
|
20
|
+
development_dependencies:
|
21
|
+
rubygems-tasks: ~> 0.2
|
22
|
+
rspec: ~> 2.0
|
23
|
+
yard: ~> 0.8
|
data/lib/ffi/pcap.rb
CHANGED
@@ -1,22 +1,16 @@
|
|
1
|
-
begin; require 'rubygems'; rescue LoadError; end
|
2
|
-
|
3
1
|
require 'ffi_dry'
|
4
2
|
|
5
3
|
module FFI
|
6
|
-
module PCap
|
7
|
-
|
4
|
+
module PCap
|
5
|
+
extend FFI::Library
|
8
6
|
|
9
|
-
|
10
|
-
ffi_lib "wpcap"
|
11
|
-
rescue LoadError
|
12
|
-
ffi_lib "pcap"
|
7
|
+
ffi_lib ['pcap', 'libpcap.so.1', 'wpcap']
|
13
8
|
end
|
14
|
-
|
9
|
+
|
10
|
+
Pcap = PCap
|
15
11
|
end
|
16
12
|
|
17
13
|
require 'ffi/pcap/crt'
|
18
|
-
|
19
|
-
require 'ffi/pcap/version'
|
20
14
|
require 'ffi/pcap/exceptions'
|
21
15
|
|
22
16
|
# FFI typedefs, pointer wrappers, and struct
|
@@ -28,7 +22,8 @@ require 'ffi/pcap/file_header'
|
|
28
22
|
require 'ffi/pcap/time_val'
|
29
23
|
require 'ffi/pcap/packet_header'
|
30
24
|
require 'ffi/pcap/stat'
|
31
|
-
require 'ffi/pcap/
|
25
|
+
require 'ffi/pcap/bpf_instruction'
|
26
|
+
require 'ffi/pcap/bpf_program'
|
32
27
|
require 'ffi/pcap/dumper'
|
33
28
|
|
34
29
|
# Ruby FFI function bindings, sugar, and misc wrappers
|
@@ -39,4 +34,3 @@ require 'ffi/pcap/packet'
|
|
39
34
|
require 'ffi/pcap/live'
|
40
35
|
require 'ffi/pcap/offline'
|
41
36
|
require 'ffi/pcap/dead'
|
42
|
-
|
data/lib/ffi/pcap/addr.rb
CHANGED
@@ -1,21 +1,22 @@
|
|
1
|
-
|
2
1
|
module FFI
|
3
|
-
module PCap
|
2
|
+
module PCap
|
3
|
+
#
|
4
|
+
# Representation of an interface address.
|
5
|
+
#
|
6
|
+
# See pcap_addr struct in `pcap.h`
|
7
|
+
#
|
8
|
+
class Addr < FFI::Struct
|
4
9
|
|
5
|
-
|
6
|
-
#
|
7
|
-
# See pcap_addr struct in pcap.h
|
8
|
-
class Addr < FFI::Struct
|
9
|
-
include FFI::DRY::StructHelper
|
10
|
+
include FFI::DRY::StructHelper
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
dsl_layout do
|
13
|
+
p_struct :next, ::FFI::PCap::Addr
|
14
|
+
p_struct :addr, ::FFI::PCap::SockAddr, :desc => 'address'
|
15
|
+
p_struct :netmask, ::FFI::PCap::SockAddr, :desc => 'netmask of the address'
|
16
|
+
p_struct :broadcast, ::FFI::PCap::SockAddr, :desc => 'broadcast for the address'
|
17
|
+
p_struct :dest_addr, ::FFI::PCap::SockAddr, :desc => 'p2p destination for address'
|
18
|
+
end
|
18
19
|
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
|
-
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'ffi/pcap/typedefs'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
module PCap
|
5
|
+
#
|
6
|
+
# Includes structures defined in `pcap-bpf.h`
|
7
|
+
#
|
8
|
+
# Berkeley Packet Filter instruction data structure.
|
9
|
+
#
|
10
|
+
# See bpf_insn struct in `pcap-bpf.h`
|
11
|
+
#
|
12
|
+
class BPFInstruction < FFI::Struct
|
13
|
+
|
14
|
+
include FFI::DRY::StructHelper
|
15
|
+
|
16
|
+
dsl_layout do
|
17
|
+
field :code, :ushort
|
18
|
+
field :jt, :uchar
|
19
|
+
field :jf, :uchar
|
20
|
+
field :k, :bpf_int32
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'ffi/pcap/bpf_instruction'
|
2
|
+
require 'ffi/pcap/data_link'
|
3
|
+
|
4
|
+
module FFI
|
5
|
+
module PCap
|
6
|
+
#
|
7
|
+
# Structure for `pcap_compile()`, `pcap_setfilter()`, etc.
|
8
|
+
#
|
9
|
+
# See bpf_program struct in `pcap-bpf.h`
|
10
|
+
#
|
11
|
+
class BPFProgram < FFI::Struct
|
12
|
+
|
13
|
+
include FFI::DRY::StructHelper
|
14
|
+
|
15
|
+
dsl_layout do
|
16
|
+
field :bf_len, :uint
|
17
|
+
field :bf_insn, :pointer
|
18
|
+
end
|
19
|
+
|
20
|
+
def instructions
|
21
|
+
i = 0
|
22
|
+
sz = BPFInstruction.size
|
23
|
+
|
24
|
+
Array.new(self.bf_len) do
|
25
|
+
ins = BPFInstruction.new( self[:bf_insn] + i )
|
26
|
+
i += sz
|
27
|
+
ins
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def free!
|
32
|
+
unless @closed
|
33
|
+
@freed = true
|
34
|
+
PCap.pcap_freecode(self)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def freed?
|
39
|
+
@freed == true
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Compiles a bpf filter without a pcap device being open. Downside is
|
44
|
+
# no error messages are available, whereas they are when you use
|
45
|
+
# open_dead() and use compile() on the resulting Dead.
|
46
|
+
#
|
47
|
+
# @param [Hash] opts
|
48
|
+
# Additional options for compile
|
49
|
+
#
|
50
|
+
# @option opts [optional, DataLink, Integer, String, Symbol] :datalink
|
51
|
+
# DataLink layer type. The argument type will be resolved to a
|
52
|
+
# DataLink value if possible. Defaults to data-link layer type NULL.
|
53
|
+
#
|
54
|
+
# @option opts [optional, Integer] :snaplen
|
55
|
+
# The snapshot length for the filter. Defaults to SNAPLEN
|
56
|
+
#
|
57
|
+
# @option opts [optional, Integer] :optimize
|
58
|
+
# Optimization flag. 0 means don't optimize. Defaults to 1.
|
59
|
+
#
|
60
|
+
# @option opts [optional, Integer] :netmask
|
61
|
+
# A 32-bit number representing the IPv4 netmask of the network on
|
62
|
+
# which packets are being captured. It is only used when checking
|
63
|
+
# for IPv4 broadcast addresses in the filter program.
|
64
|
+
# Default: 0 (unspecified netmask)
|
65
|
+
#
|
66
|
+
# @return [BPFProgram]
|
67
|
+
# If no errors occur, a compiled BPFProgram is returned.
|
68
|
+
#
|
69
|
+
def self.compile(expr, opts={})
|
70
|
+
datalink = (opts[:datalink] || 1)
|
71
|
+
dl = datalink.kind_of?(DataLink) ? datalink : DataLink.new(datalink)
|
72
|
+
slen = (opts[:snaplen] || DEFAULT_SNAPLEN)
|
73
|
+
optimize = (opts[:optimize] || 1)
|
74
|
+
mask = (opts[:netmask] || 0)
|
75
|
+
|
76
|
+
code = new()
|
77
|
+
r = PCap.pcap_compile_nopcap(slen, dl.value, code, expr, optimize, mask)
|
78
|
+
|
79
|
+
raise(LibError, "pcap_compile_nopcap(): unspecified error") if r < 0
|
80
|
+
return code
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/ffi/pcap/bsd.rb
CHANGED
@@ -1,98 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
require '
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
typedef :uint32, :in_addr_t
|
11
|
-
typedef :uint16, :in_port_t
|
12
|
-
|
13
|
-
# contains AF_* constants culled from Ruby's ::Socket
|
14
|
-
module AF
|
15
|
-
include ::FFI::DRY::ConstMap
|
16
|
-
slurp_constants(::Socket, "AF_")
|
17
|
-
def self.list; @@list ||= super() ; end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Common abstract superclass for all sockaddr struct classes
|
21
|
-
#
|
22
|
-
class SockAddrFamily < ::FFI::Struct
|
23
|
-
include ::FFI::DRY::StructHelper
|
24
|
-
|
25
|
-
# returns an address family name for the :family struct member value
|
26
|
-
def lookup_family
|
27
|
-
AF[ self[:family] ]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# generic sockaddr, always good to have around
|
32
|
-
#
|
33
|
-
class SockAddr < SockAddrFamily
|
34
|
-
dsl_layout do
|
35
|
-
field :len, :uint8, :desc => 'total length of struct'
|
36
|
-
field :family, :sa_family_t, :desc => 'address family (AF_*)'
|
37
|
-
field :data, :char, :desc => 'variable length bound by :len'
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
# Used to represent a 32-bit IPv4 address in a sock_addr_in structure
|
43
|
-
#
|
44
|
-
class InAddr < ::FFI::Struct
|
45
|
-
include ::FFI::DRY::StructHelper
|
46
|
-
dsl_layout { field :in_addr, :in_addr_t, :desc => 'inet address' }
|
47
|
-
end
|
48
|
-
|
49
|
-
# sockaddr inet, always good to have around
|
50
|
-
#
|
51
|
-
class SockAddrIn < SockAddrFamily
|
52
|
-
dsl_layout do
|
53
|
-
field :len, :uint8, :desc => 'length of structure (16)'
|
54
|
-
field :family, :sa_family_t, :desc => 'address family (AF_INET)'
|
55
|
-
field :port, :in_port_t, :desc => '16-bit TCP or UDP port number'
|
56
|
-
field :addr, :in_addr_t, :desc => '32-bit IPv4 address'
|
57
|
-
array :_sa_zero, [:uint8,8], :desc => 'unused'
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# Used to represent an IPv6 address in a sock_addr_in6 structure
|
62
|
-
#
|
63
|
-
class In6Addr < ::FFI::Struct
|
64
|
-
include ::FFI::DRY::StructHelper
|
65
|
-
dsl_layout { array :s6_addr, [:uint8, 16], :desc => 'IPv6 address' }
|
66
|
-
end
|
67
|
-
|
68
|
-
# IPv6 socket address
|
69
|
-
#
|
70
|
-
class SockAddrIn6 < SockAddrFamily
|
71
|
-
dsl_layout do
|
72
|
-
field :len, :uint8, :desc => 'length of structure(24)'
|
73
|
-
field :family, :sa_family_t, :desc => 'address family (AF_INET6)'
|
74
|
-
field :port, :in_port_t, :desc => 'transport layer port'
|
75
|
-
field :flowinfo, :uint32, :desc => 'priority & flow label'
|
76
|
-
struct :addr, ::FFI::PCap::In6Addr, :desc => 'IPv6 address'
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
# data-link socket address
|
82
|
-
#
|
83
|
-
class SockAddrDl < SockAddrFamily
|
84
|
-
dsl_layout do
|
85
|
-
field :len, :uint8, :desc => 'length of structure(variable)'
|
86
|
-
field :family, :sa_family_t, :desc => 'address family (AF_LINK)'
|
87
|
-
field :sdl_index, :uint16, :desc => 'system assigned index, if > 0'
|
88
|
-
field :dltype, :uint8, :desc => 'IFT_ETHER, etc. from net/if_types.h'
|
89
|
-
field :nlen, :uint8, :desc => 'name length, from :_data'
|
90
|
-
field :alen, :uint8, :desc => 'link-layer addres-length'
|
91
|
-
field :slen, :uint8, :desc => 'link-layer selector length'
|
92
|
-
field :_data, :char, :desc => 'minimum work area=12, can be larger'
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
1
|
+
require 'ffi/pcap/bsd/typedefs'
|
2
|
+
require 'ffi/pcap/bsd/af'
|
3
|
+
require 'ffi/pcap/bsd/in_addr'
|
4
|
+
require 'ffi/pcap/bsd/sock_addr'
|
5
|
+
require 'ffi/pcap/bsd/sock_addr_family'
|
6
|
+
require 'ffi/pcap/bsd/sock_addr_in'
|
7
|
+
require 'ffi/pcap/bsd/sock_addr_dl'
|
8
|
+
require 'ffi/pcap/bsd/in6_addr'
|
9
|
+
require 'ffi/pcap/bsd/sock_addr_in6'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
module PCap
|
5
|
+
#
|
6
|
+
# Contains `AF_*` constants culled from Ruby's ::Socket
|
7
|
+
#
|
8
|
+
module AF
|
9
|
+
include ::FFI::DRY::ConstMap
|
10
|
+
|
11
|
+
slurp_constants(::Socket, "AF_")
|
12
|
+
|
13
|
+
def self.list
|
14
|
+
@@list ||= super()
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module FFI
|
2
|
+
module PCap
|
3
|
+
#
|
4
|
+
# Used to represent an IPv6 address in a sock_addr_in6 structure
|
5
|
+
#
|
6
|
+
class In6Addr < ::FFI::Struct
|
7
|
+
|
8
|
+
include ::FFI::DRY::StructHelper
|
9
|
+
|
10
|
+
dsl_layout do
|
11
|
+
array :s6_addr, [:uint8, 16], :desc => 'IPv6 address'
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'ffi/pcap/bsd/typedefs'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
module PCap
|
5
|
+
#
|
6
|
+
# Used to represent a 32-bit IPv4 address in a sock_addr_in structure
|
7
|
+
#
|
8
|
+
class InAddr < ::FFI::Struct
|
9
|
+
|
10
|
+
include ::FFI::DRY::StructHelper
|
11
|
+
|
12
|
+
dsl_layout do
|
13
|
+
field :in_addr, :in_addr_t, :desc => 'inet address'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'ffi/pcap/bsd/typedefs'
|
2
|
+
require 'ffi/pcap/bsd/sock_addr_family'
|
3
|
+
|
4
|
+
module FFI
|
5
|
+
module PCap
|
6
|
+
#
|
7
|
+
# generic sockaddr, always good to have around
|
8
|
+
#
|
9
|
+
class SockAddr < SockAddrFamily
|
10
|
+
|
11
|
+
dsl_layout do
|
12
|
+
field :len, :uint8, :desc => 'total length of struct'
|
13
|
+
field :family, :sa_family_t, :desc => 'address family (AF_*)'
|
14
|
+
field :data, :char, :desc => 'variable length bound by :len'
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'ffi/pcap/bsd/typedefs'
|
2
|
+
require 'ffi/pcap/bsd/sock_addr_family'
|
3
|
+
|
4
|
+
module FFI
|
5
|
+
module PCap
|
6
|
+
#
|
7
|
+
# data-link socket address
|
8
|
+
#
|
9
|
+
class SockAddrDl < SockAddrFamily
|
10
|
+
|
11
|
+
dsl_layout do
|
12
|
+
field :len, :uint8, :desc => 'length of structure(variable)'
|
13
|
+
field :family, :sa_family_t, :desc => 'address family (AF_LINK)'
|
14
|
+
field :sdl_index, :uint16, :desc => 'system assigned index, if > 0'
|
15
|
+
field :dltype, :uint8, :desc => 'IFT_ETHER, etc. from net/if_types.h'
|
16
|
+
field :nlen, :uint8, :desc => 'name length, from :_data'
|
17
|
+
field :alen, :uint8, :desc => 'link-layer addres-length'
|
18
|
+
field :slen, :uint8, :desc => 'link-layer selector length'
|
19
|
+
field :_data, :char, :desc => 'minimum work area=12, can be larger'
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'ffi/pcap/bsd/af'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
module PCap
|
5
|
+
#
|
6
|
+
# Common abstract superclass for all sockaddr struct classes
|
7
|
+
#
|
8
|
+
class SockAddrFamily < ::FFI::Struct
|
9
|
+
|
10
|
+
include ::FFI::DRY::StructHelper
|
11
|
+
|
12
|
+
# returns an address family name for the :family struct member value
|
13
|
+
def lookup_family
|
14
|
+
AF[self[:family]]
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|