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.
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