ffi-pcap 0.2.0 → 0.2.1
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.
- 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
|