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
@@ -1,57 +1,27 @@
1
- module FFI
2
- module PCap
3
- # As returned by pcap_stats()
4
- #
5
- # See pcap_stat struct in pcap.h.
6
- class Stat < FFI::Struct
7
- include FFI::DRY::StructHelper
8
-
9
- dsl_layout do
10
- field :ps_recv, :uint, :desc => "number of packets received"
11
- field :ps_drop, :uint, :desc => "numer of packets dropped"
12
- field :ps_ifdrop, :uint, :desc => "drops by interface (not yet supported)"
13
- # bs_capt field intentionally left off (WIN32 only)
14
- end
15
-
16
- alias received ps_recv
17
- alias dropped ps_drop
18
- alias interface_dropped ps_ifdrop
1
+ require 'ffi/pcap/stat_ex'
19
2
 
20
- end
3
+ module FFI
4
+ module PCap
5
+ #
6
+ # As returned by `pcap_stats`.
7
+ #
8
+ # See `pcap_stat` struct in `pcap.h`.
9
+ #
10
+ class Stat < FFI::Struct
21
11
 
22
- # As returned by pcap_stats_ex() (MSDOS only)
23
- #
24
- # See pcap_stat_ex struct in pcap.h
25
- class StatEx < FFI::Struct
26
- include FFI::DRY::StructHelper
12
+ include FFI::DRY::StructHelper
27
13
 
28
- dsl_layout do
29
- field :rx_packets, :ulong, :desc => "total packets received"
30
- field :tx_packets, :ulong, :desc => "total packets transmitted"
31
- field :rx_bytes, :ulong, :desc => "total bytes received"
32
- field :tx_bytes, :ulong, :desc => "total bytes transmitted"
33
- field :rx_errors, :ulong, :desc => "bad packets received"
34
- field :tx_errors, :ulong, :desc => "packet transmit problems"
35
- field :rx_dropped, :ulong, :desc => "no space in Rx buffers"
36
- field :tx_dropped, :ulong, :desc => "no space available for Tx"
37
- field :multicast, :ulong, :desc => "multicast packets received"
38
- field :collisions, :ulong
14
+ dsl_layout do
15
+ field :ps_recv, :uint, :desc => "number of packets received"
16
+ field :ps_drop, :uint, :desc => "numer of packets dropped"
17
+ field :ps_ifdrop, :uint, :desc => "drops by interface (not yet supported)"
18
+ # bs_capt field intentionally left off (WIN32 only)
19
+ end
39
20
 
40
- # detailed rx errors
41
- field :rx_length_errors, :ulong
42
- field :rx_over_errors, :ulong, :desc => "ring buff overflow"
43
- field :rx_crc_errors, :ulong, :desc => "pkt with crc error"
44
- field :rx_frame_errors, :ulong, :desc => "frame alignment errors"
45
- field :rx_fifo_errors, :ulong, :desc => "fifo overrun"
46
- field :rx_missed_errors, :ulong, :desc => "missed packet"
21
+ alias received ps_recv
22
+ alias dropped ps_drop
23
+ alias interface_dropped ps_ifdrop
47
24
 
48
- # detailed tx_errors
49
- field :tx_aborted_errors, :ulong
50
- field :tx_carrier_errors, :ulong
51
- field :tx_fifo_errors, :ulong
52
- field :tx_heartbeat_errors, :ulong
53
- field :tx_window_errors, :ulong
54
25
  end
55
26
  end
56
27
  end
57
- end
@@ -0,0 +1,42 @@
1
+ module FFI
2
+ module PCap
3
+ #
4
+ # As returned by `pcap_stats_ex()` (MSDOS only).
5
+ #
6
+ # See `pcap_stat_ex` struct in `pcap.h`.
7
+ #
8
+ class StatEx < FFI::Struct
9
+
10
+ include FFI::DRY::StructHelper
11
+
12
+ dsl_layout do
13
+ field :rx_packets, :ulong, :desc => "total packets received"
14
+ field :tx_packets, :ulong, :desc => "total packets transmitted"
15
+ field :rx_bytes, :ulong, :desc => "total bytes received"
16
+ field :tx_bytes, :ulong, :desc => "total bytes transmitted"
17
+ field :rx_errors, :ulong, :desc => "bad packets received"
18
+ field :tx_errors, :ulong, :desc => "packet transmit problems"
19
+ field :rx_dropped, :ulong, :desc => "no space in Rx buffers"
20
+ field :tx_dropped, :ulong, :desc => "no space available for Tx"
21
+ field :multicast, :ulong, :desc => "multicast packets received"
22
+ field :collisions, :ulong
23
+
24
+ # detailed rx errors
25
+ field :rx_length_errors, :ulong
26
+ field :rx_over_errors, :ulong, :desc => "ring buff overflow"
27
+ field :rx_crc_errors, :ulong, :desc => "pkt with crc error"
28
+ field :rx_frame_errors, :ulong, :desc => "frame alignment errors"
29
+ field :rx_fifo_errors, :ulong, :desc => "fifo overrun"
30
+ field :rx_missed_errors, :ulong, :desc => "missed packet"
31
+
32
+ # detailed tx_errors
33
+ field :tx_aborted_errors, :ulong
34
+ field :tx_carrier_errors, :ulong
35
+ field :tx_fifo_errors, :ulong
36
+ field :tx_heartbeat_errors, :ulong
37
+ field :tx_window_errors, :ulong
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -1,48 +1,62 @@
1
1
  module FFI
2
- module PCap
3
- class TimeVal < FFI::Struct
4
- include FFI::DRY::StructHelper
2
+ module PCap
3
+ class TimeVal < FFI::Struct
5
4
 
6
- dsl_layout do
7
- field :tv_sec, :time_t
8
- field :tv_usec, :suseconds_t
9
- end
5
+ include FFI::DRY::StructHelper
10
6
 
11
- def initialize(*args)
12
- if args.size == 1 and (t=args[0]).kind_of?(Time)
13
- self.time = t
14
- else
15
- super(*args)
7
+ dsl_layout do
8
+ field :tv_sec, :time_t
9
+ field :tv_usec, :suseconds_t
16
10
  end
17
- end
18
11
 
19
- alias sec tv_sec
20
- alias usec tv_usec
12
+ #
13
+ # Initializes the new {TimeVal}.
14
+ #
15
+ # @param [Time, FFI::Pointer] timeval
16
+ # A Time object or a pointer to another {TimeVal}.
17
+ #
18
+ def initialize(timeval=nil)
19
+ case timeval
20
+ when Time
21
+ super()
21
22
 
22
- # Returns the time value as a ruby Time object.
23
- #
24
- # @return [Time]
25
- # A ruby time object derived from this TimeVal.
26
- def time
27
- Time.at(self.tv_sec, self.tv_usec)
28
- end
23
+ self.time = timeval
24
+ when Pointer then super(timeval)
25
+ else super()
26
+ end
27
+ end
29
28
 
30
- alias to_time time
31
-
32
- # Sets the time value from a ruby Time object
33
- #
34
- # @param [Time] t
35
- # A ruby time object from which to set the time.
36
- #
37
- # @return [Time]
38
- # Returns the same Time object supplied per convention.
39
- #
40
- def time=(t)
41
- self.tv_sec = t.tv_sec
42
- self.tv_usec = t.tv_usec
43
- return t
44
- end
29
+ alias sec tv_sec
30
+ alias usec tv_usec
31
+
32
+ #
33
+ # Returns the time value as a ruby Time object.
34
+ #
35
+ # @return [Time]
36
+ # A ruby time object derived from this TimeVal.
37
+ #
38
+ def time
39
+ Time.at(self.tv_sec, self.tv_usec)
40
+ end
45
41
 
42
+ alias to_time time
43
+
44
+ #
45
+ # Sets the time value from a ruby Time object
46
+ #
47
+ # @param [Time] new_time
48
+ # A ruby time object from which to set the time.
49
+ #
50
+ # @return [Time]
51
+ # Returns the same Time object supplied per convention.
52
+ #
53
+ def time=(new_time)
54
+ self.tv_sec = new_time.tv_sec
55
+ self.tv_usec = new_time.tv_usec
56
+
57
+ return new_time
58
+ end
59
+
60
+ end
46
61
  end
47
62
  end
48
- end
@@ -1,27 +1,23 @@
1
1
  module FFI
2
- module PCap
3
- typedef :pointer, :FILE
2
+ module PCap
3
+ extend FFI::Library
4
4
 
5
- typedef :int, :bpf_int32
6
- typedef :uint, :bpf_uint32
5
+ typedef :pointer, :FILE
7
6
 
8
- enum :pcap_direction_t, [
9
- :pcap_d_inout,
10
- :pcap_d_in,
11
- :pcap_d_out
12
- ]
7
+ typedef :int, :bpf_int32
8
+ typedef :uint, :bpf_uint32
13
9
 
14
- # For Win32-only pcap_setmode()
15
- enum :pcap_w32_modes_enum, [ :capt, :stat, :mon ]
10
+ enum :pcap_direction_t, [
11
+ :pcap_d_inout,
12
+ :pcap_d_in,
13
+ :pcap_d_out
14
+ ]
16
15
 
17
- typedef :pointer, :pcap_t
18
- typedef :pointer, :pcap_dumper_t
19
- typedef :pointer, :pcap_addr_t
16
+ # For Win32-only pcap_setmode()
17
+ enum :pcap_w32_modes_enum, [ :capt, :stat, :mon ]
20
18
 
21
- # add some of the more temperamental FFI types if needed
22
- [ [:long, :time_t],
23
- [:uint32, :suseconds_t],
24
- ].each {|t, d| begin; find_type(d); rescue TypeError; typedef t,d; end }
25
-
26
- end
19
+ typedef :pointer, :pcap_t
20
+ typedef :pointer, :pcap_dumper_t
21
+ typedef :pointer, :pcap_addr_t
22
+ end
27
23
  end
@@ -1,65 +1,69 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe DataLink do
4
- before(:all) do
5
- @datalink = DataLink.new(0)
6
- end
4
+ subject { described_class.new(0) }
7
5
 
8
6
  it "should map datalink names to datalink layer type values" do
9
- DataLink.name_to_val(:en10mb).should == 1
7
+ described_class.name_to_val(:en10mb).should == 1
10
8
  end
11
9
 
12
10
  it "should map datalink layer type values to datalink names" do
13
- DataLink.val_to_name(1).should == "EN10MB"
11
+ described_class.val_to_name(1).should == "EN10MB"
14
12
  end
15
13
 
16
14
  it "should be initialized from a pcap datalink value" do
17
- @datalink.name.should == 'NULL'
15
+ subject.name.should == 'NULL'
18
16
  end
19
17
 
20
- it "should support initialization from a pcap datalink name symbol" do
21
- @datalink = DataLink.new(:null)
22
- DataLink.should === @datalink
18
+ it "should have a description" do
19
+ subject.description.should_not be_empty
23
20
  end
24
21
 
25
- it "should support initialization from a pcap datalink name string" do
26
- dl = DataLink.new('en10mb')
27
- DataLink.should === dl
28
- end
22
+ describe "#initialize" do
23
+ it "should support initialization from a pcap datalink name Symbol" do
24
+ link = described_class.new(:null)
29
25
 
30
- it "should allow equality comparison against numeric values" do
31
- (@datalink == 0).should == true
32
- (@datalink == 1).should == false
33
- end
26
+ link.name.should == 'NULL'
27
+ end
34
28
 
35
- it "should allow equality comparison against String names" do
36
- (@datalink == "null").should == true
37
- (@datalink == "en10mb").should == false
29
+ it "should support initialization from a pcap datalink name String" do
30
+ link = described_class.new('en10mb')
31
+
32
+ link.name.should == 'EN10MB'
33
+ end
38
34
  end
39
35
 
40
- it "should allow equality comparison against Symbol names" do
41
- (@datalink == :null).should == true
42
- (@datalink == :en10mb).should == false
43
- end
36
+ describe "#==" do
37
+ it "should allow equality comparison against numeric values" do
38
+ (subject == 0).should == true
39
+ (subject == 1).should == false
40
+ end
44
41
 
45
- it "should allow comparison against another DataLink" do
46
- (@datalink == DataLink.new(0)).should == true
47
- (@datalink == DataLink.new(1)).should == false
48
- end
42
+ it "should allow equality comparison against String names" do
43
+ (subject == "null").should == true
44
+ (subject == "en10mb").should == false
45
+ end
49
46
 
50
- it "should still compare correctly against any other object" do
51
- (@datalink == Object.new).should == false
52
- end
47
+ it "should allow equality comparison against Symbol names" do
48
+ (subject == :null).should == true
49
+ (subject == :en10mb).should == false
50
+ end
53
51
 
54
- it "should have a description" do
55
- @datalink.description.should_not be_empty
52
+ it "should allow comparison against another described_class" do
53
+ (subject == described_class.new(0)).should == true
54
+ (subject == described_class.new(1)).should == false
55
+ end
56
+
57
+ it "should still compare correctly against any other object" do
58
+ (subject == Object.new).should == false
59
+ end
56
60
  end
57
61
 
58
62
  it "should convert to an Integer for the DLT value" do
59
- @datalink.to_i.should == 0
63
+ subject.to_i.should == 0
60
64
  end
61
65
 
62
66
  it "should convert to a String for the DLT name" do
63
- @datalink.to_s.should == 'NULL'
67
+ subject.to_s.should == 'NULL'
64
68
  end
65
69
  end
@@ -26,9 +26,5 @@ describe Dead do
26
26
 
27
27
  @pcap.close
28
28
  end
29
-
30
-
31
29
  end
32
-
33
30
  end
34
-
@@ -1,17 +1,15 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ErrorBuffer do
4
- before(:all) do
5
- @errbuf = ErrorBuffer.create
6
- end
7
-
8
- it "should have a size of 256" do
9
- @errbuf.size.should == 256
4
+ it "should have a default size of 256" do
5
+ subject.size.should == 256
10
6
  end
11
7
 
12
8
  it "should return an error message with to_s" do
13
- @errbuf.to_s.should be_empty
14
- FFI::PCap.pcap_open_offline("/this/file/wont/exist/#{rand(0xFFFF)}", @errbuf )
15
- @errbuf.to_s.should_not be_empty
9
+ subject.to_s.should be_empty
10
+
11
+ PCap.pcap_open_offline("/this/file/wont/exist",subject)
12
+
13
+ subject.to_s.should_not be_empty
16
14
  end
17
15
  end
@@ -1,28 +1,31 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe FileHeader do
4
- before(:all) do
5
- @file_header = FileHeader.new( :raw => File.read(PCAP_TESTFILE) )
4
+ let(:pcap_file) do
5
+ File.open(PCAP_TESTFILE,'rb') do |file|
6
+ file.read
7
+ end
6
8
  end
7
9
 
10
+ subject { described_class.new(:raw => pcap_file) }
11
+
8
12
  it "should parse a pcap file correctly" do
9
- @file_header.magic.should == 0xa1b2c3d4
10
- @file_header.version_major.should == 2
11
- @file_header.version_minor.should == 4
12
- @file_header.thiszone.should == 0
13
- @file_header.sigfigs.should == 0
14
- @file_header.snaplen.should == 96
15
- @file_header.linktype.should == 1
13
+ subject.magic.should == 0xa1b2c3d4
14
+ subject.version_major.should == 2
15
+ subject.version_minor.should == 4
16
+ subject.thiszone.should == 0
17
+ subject.sigfigs.should == 0
18
+ subject.snaplen.should == 96
19
+ subject.linktype.should == 1
16
20
  end
17
21
 
18
22
  it "should return a file format version string" do
19
- String.should === @file_header.version
20
- @file_header.version.should == "2.4"
23
+ subject.version.should == "2.4"
21
24
  end
22
25
 
23
26
  it "should return a DataLink for the linktype using datalink()" do
24
- DataLink.should === @file_header.datalink
25
- (@file_header.datalink == :en10mb).should == true
26
- end
27
+ subject.datalink.should be_kind_of(DataLink)
27
28
 
29
+ (subject.datalink == :en10mb).should == true
30
+ end
28
31
  end