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.
Files changed (82) hide show
  1. data/.gitignore +2 -1
  2. data/.pkg_ignore +25 -0
  3. data/.rspec +1 -0
  4. data/.specopts +1 -0
  5. data/.yardopts +1 -0
  6. data/{ChangeLog.rdoc → ChangeLog.md} +15 -5
  7. data/LICENSE.txt +1 -4
  8. data/README.md +92 -0
  9. data/Rakefile +30 -20
  10. data/examples/em_selectable_pcap.rb +38 -0
  11. data/examples/em_timer.rb +26 -0
  12. data/examples/ipfw_divert.rb +28 -8
  13. data/examples/print_bytes.rb +5 -1
  14. data/examples/replay.rb +11 -0
  15. data/examples/selectable_pcap.rb +29 -0
  16. data/ffi-pcap.gemspec +60 -0
  17. data/gemspec.yml +23 -0
  18. data/lib/ffi/pcap.rb +7 -13
  19. data/lib/ffi/pcap/addr.rb +16 -15
  20. data/lib/ffi/pcap/bpf_instruction.rb +25 -0
  21. data/lib/ffi/pcap/bpf_program.rb +85 -0
  22. data/lib/ffi/pcap/bsd.rb +9 -98
  23. data/lib/ffi/pcap/bsd/af.rb +18 -0
  24. data/lib/ffi/pcap/bsd/in6_addr.rb +16 -0
  25. data/lib/ffi/pcap/bsd/in_addr.rb +18 -0
  26. data/lib/ffi/pcap/bsd/sock_addr.rb +19 -0
  27. data/lib/ffi/pcap/bsd/sock_addr_dl.rb +24 -0
  28. data/lib/ffi/pcap/bsd/sock_addr_family.rb +19 -0
  29. data/lib/ffi/pcap/bsd/sock_addr_in.rb +21 -0
  30. data/lib/ffi/pcap/bsd/sock_addr_in6.rb +20 -0
  31. data/lib/ffi/pcap/bsd/typedefs.rb +7 -0
  32. data/lib/ffi/pcap/capture_wrapper.rb +296 -256
  33. data/lib/ffi/pcap/common_wrapper.rb +152 -127
  34. data/lib/ffi/pcap/copy_handler.rb +32 -32
  35. data/lib/ffi/pcap/crt.rb +7 -10
  36. data/lib/ffi/pcap/data_link.rb +178 -153
  37. data/lib/ffi/pcap/dead.rb +42 -29
  38. data/lib/ffi/pcap/dumper.rb +39 -41
  39. data/lib/ffi/pcap/error_buffer.rb +21 -36
  40. data/lib/ffi/pcap/exceptions.rb +21 -15
  41. data/lib/ffi/pcap/file_header.rb +24 -18
  42. data/lib/ffi/pcap/in_addr.rb +4 -4
  43. data/lib/ffi/pcap/interface.rb +22 -20
  44. data/lib/ffi/pcap/live.rb +296 -252
  45. data/lib/ffi/pcap/offline.rb +50 -43
  46. data/lib/ffi/pcap/packet.rb +186 -143
  47. data/lib/ffi/pcap/packet_header.rb +20 -18
  48. data/lib/ffi/pcap/pcap.rb +269 -212
  49. data/lib/ffi/pcap/stat.rb +19 -49
  50. data/lib/ffi/pcap/stat_ex.rb +42 -0
  51. data/lib/ffi/pcap/time_val.rb +52 -38
  52. data/lib/ffi/pcap/typedefs.rb +16 -20
  53. data/spec/data_link_spec.rb +39 -35
  54. data/spec/dead_spec.rb +0 -4
  55. data/spec/error_buffer_spec.rb +7 -9
  56. data/spec/file_header_spec.rb +17 -14
  57. data/spec/live_spec.rb +12 -5
  58. data/spec/offline_spec.rb +10 -11
  59. data/spec/packet_behaviors.rb +20 -6
  60. data/spec/packet_injection_spec.rb +9 -8
  61. data/spec/packet_spec.rb +22 -26
  62. data/spec/pcap_spec.rb +52 -40
  63. data/spec/spec_helper.rb +16 -5
  64. data/spec/wrapper_behaviors.rb +0 -3
  65. data/tasks/doc.rake +69 -0
  66. data/tasks/gem.rake +200 -0
  67. data/tasks/git.rake +40 -0
  68. data/tasks/post_load.rake +34 -0
  69. data/tasks/rubyforge.rake +55 -0
  70. data/tasks/setup.rb +286 -0
  71. data/tasks/spec.rake +54 -0
  72. data/tasks/svn.rake +47 -0
  73. data/tasks/test.rake +40 -0
  74. metadata +142 -92
  75. data/README.rdoc +0 -30
  76. data/VERSION +0 -1
  77. data/lib/ffi/pcap/bpf.rb +0 -106
  78. data/lib/ffi/pcap/version.rb +0 -6
  79. data/tasks/rcov.rb +0 -6
  80. data/tasks/rdoc.rb +0 -17
  81. data/tasks/spec.rb +0 -9
  82. data/tasks/yard.rb +0 -21
@@ -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
@@ -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
- extend FFI::Library
4
+ module PCap
5
+ extend FFI::Library
8
6
 
9
- begin
10
- ffi_lib "wpcap"
11
- rescue LoadError
12
- ffi_lib "pcap"
7
+ ffi_lib ['pcap', 'libpcap.so.1', 'wpcap']
13
8
  end
14
- end
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/bpf'
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
-
@@ -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
- # Representation of an interface address.
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
- dsl_layout do
12
- p_struct :next, ::FFI::PCap::Addr
13
- p_struct :addr, ::FFI::PCap::SockAddr, :desc => 'address'
14
- p_struct :netmask, ::FFI::PCap::SockAddr, :desc => 'netmask of the address'
15
- p_struct :broadcast, ::FFI::PCap::SockAddr, :desc => 'broadcast for the address'
16
- p_struct :dest_addr, ::FFI::PCap::SockAddr, :desc => 'p2p destination for address'
17
- end
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
@@ -1,98 +1,9 @@
1
- # Here's where various BSD sockets typedefs and structures go
2
- # ... good to have around
3
- # cribbed from dnet-ffi - EM
4
-
5
- require 'socket'
6
-
7
- module FFI
8
- module PCap
9
- typedef :uint8, :sa_family_t
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