dakrone-pcap-ffi 0.0.0

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 ADDED
@@ -0,0 +1,6 @@
1
+ doc
2
+ pkg
3
+ tmp/*
4
+ .DS_Store
5
+ *.swp
6
+ *~
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.1.0 / 2009-04-29
2
+
3
+ * Initial release.
4
+
data/Manifest.txt ADDED
@@ -0,0 +1,40 @@
1
+ History.txt
2
+ Manifest.txt
3
+ Rakefile
4
+ README.txt
5
+ examples/print_bytes.rb
6
+ lib/pcap.rb
7
+ lib/pcap/exceptions.rb
8
+ lib/pcap/exceptions/read_error.rb
9
+ lib/pcap/typedefs.rb
10
+ lib/pcap/time_val.rb
11
+ lib/pcap/in_addr.rb
12
+ lib/pcap/sock_addr.rb
13
+ lib/pcap/sock_addr_in.rb
14
+ lib/pcap/if.rb
15
+ lib/pcap/addr.rb
16
+ lib/pcap/file_header.rb
17
+ lib/pcap/packet_header.rb
18
+ lib/pcap/packet.rb
19
+ lib/pcap/packets.rb
20
+ lib/pcap/packets/typedefs.rb
21
+ lib/pcap/packets/ethernet.rb
22
+ lib/pcap/packets/ip.rb
23
+ lib/pcap/packets/tcp.rb
24
+ lib/pcap/stat.rb
25
+ lib/pcap/data_link.rb
26
+ lib/pcap/error_buffer.rb
27
+ lib/pcap/handler.rb
28
+ lib/pcap/dumper.rb
29
+ lib/pcap/version.rb
30
+ lib/pcap/ffi.rb
31
+ lib/pcap/pcap.rb
32
+ tasks/spec.rb
33
+ spec/spec_helper.rb
34
+ spec/helpers/dumps.rb
35
+ spec/dumps/simple_tcp.pcap
36
+ spec/error_buffer.rb
37
+ spec/data_link_spec.rb
38
+ spec/handler_examples.rb
39
+ spec/handler_spec.rb
40
+ spec/pcap_spec.rb
data/README.txt ADDED
@@ -0,0 +1,41 @@
1
+ = pcap-ffi
2
+
3
+ * http://github.com/postmodern/pcap-ffi/
4
+ * Postmodern (postmodern.mod3 at gmail.com)
5
+
6
+ == DESCRIPTION:
7
+
8
+ Ruby FFI bindings for libpcap.
9
+
10
+ == FEATURES:
11
+
12
+ == EXAMPLES:
13
+
14
+ == INSTALL:
15
+
16
+ $ sudo gem install pcap-ffi
17
+
18
+ == LICENSE:
19
+
20
+ The MIT License
21
+
22
+ Copyright (c) 2009 Hal Brodigan
23
+
24
+ Permission is hereby granted, free of charge, to any person obtaining
25
+ a copy of this software and associated documentation files (the
26
+ 'Software'), to deal in the Software without restriction, including
27
+ without limitation the rights to use, copy, modify, merge, publish,
28
+ distribute, sublicense, and/or sell copies of the Software, and to
29
+ permit persons to whom the Software is furnished to do so, subject to
30
+ the following conditions:
31
+
32
+ The above copyright notice and this permission notice shall be
33
+ included in all copies or substantial portions of the Software.
34
+
35
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
36
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
37
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
38
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
39
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
40
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
41
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require './lib/pcap/version.rb'
5
+ require './tasks/spec.rb'
6
+
7
+ # Generate a gem using jeweler
8
+ begin
9
+ require 'jeweler'
10
+ Jeweler::Tasks.new do |gemspec|
11
+ gemspec.rubyforge_project = 'pcap-ffi'
12
+ gemspec.name = "pcap-ffi"
13
+ gemspec.summary = "FFI bindings for libpcap"
14
+ gemspec.email = "postmodern.mod3@gmail.com"
15
+ gemspec.homepage = "http://github.com/postmodern/pcap-ffi"
16
+ gemspec.description = "Bindings to sniff packets using the FFI interface in Ruby."
17
+ gemspec.authors = ["Postmodern, Dakrone"]
18
+ end
19
+ rescue LoadError
20
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
21
+ end
22
+
23
+
24
+ # vim: syntax=Ruby
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'pcap'
5
+
6
+ include FFI
7
+
8
+ pcap = PCap.open_live(:device => ARGV[0]) do |user,header,bytes|
9
+ puts "#{header.timestamp}:"
10
+
11
+ header.captured.times { |i|
12
+ print ' %.2x' % bytes.get_uchar(i)
13
+ }
14
+ putc "\n"
15
+ end
16
+
17
+ pcap.loop
data/lib/pcap/addr.rb ADDED
@@ -0,0 +1,37 @@
1
+ require 'pcap/typedefs'
2
+ require 'pcap/sock_addr'
3
+
4
+ require 'ffi/struct'
5
+
6
+ module FFI
7
+ module PCap
8
+ class Addr < FFI::Struct
9
+ layout :next, :pointer,
10
+ :addr, :pointer,
11
+ :netmask, :pointer,
12
+ :broadaddr, :pointer,
13
+ :dstaddr, :pointer
14
+
15
+ def next
16
+ Addr.new(self[:next])
17
+ end
18
+
19
+ def addr
20
+ SockAddr.new(self[:addr])
21
+ end
22
+
23
+ def netmask
24
+ SockAddr.new(self[:netmask])
25
+ end
26
+
27
+ def broadcast
28
+ SockAddr.new(self[:broadaddr])
29
+ end
30
+
31
+ def dest_addr
32
+ SockAddr.new(self[:destaddr])
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,53 @@
1
+ module FFI
2
+ module PCap
3
+ class DataLink
4
+
5
+ # PCap datalink numeric value
6
+ attr_reader :value
7
+
8
+ # DataLink name
9
+ attr_reader :name
10
+
11
+ #
12
+ # Creates a new DataLink object with the specified _value_.
13
+ #
14
+ def initialize(value)
15
+ @value = value
16
+ @name = PCap.pcap_datalink_val_to_name(@value)
17
+ end
18
+
19
+ def self.[](name)
20
+ PCap.pcap_datalink_name_to_val(name.to_s.downcase)
21
+ end
22
+
23
+ #
24
+ # Returns the description of the datalink.
25
+ #
26
+ def description
27
+ PCap.pcap_datalink_val_to_description(@value)
28
+ end
29
+
30
+ #
31
+ # Returns the numeric value of the datalink.
32
+ #
33
+ def to_i
34
+ @value
35
+ end
36
+
37
+ #
38
+ # Returns the String form of the datalink.
39
+ #
40
+ def to_s
41
+ @name
42
+ end
43
+
44
+ #
45
+ # Inspects the datalink.
46
+ #
47
+ def inspect
48
+ "#<#{self.class}: #{@name}>"
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,39 @@
1
+ require 'pcap/ffi'
2
+
3
+ require 'ffi'
4
+
5
+ module FFI
6
+ module PCap
7
+ class Dumper < FFI::MemoryPointer
8
+
9
+ def initialize(dumper)
10
+ @dumper = dumper
11
+ end
12
+
13
+ def write(header,bytes)
14
+ PCap.pcap_dump(@dumper,header,bytes)
15
+ end
16
+
17
+ def tell
18
+ PCap.pcap_dump_ftell(@dumper)
19
+ end
20
+
21
+ def flush
22
+ PCap.pcap_dump_flush(@dumper)
23
+ end
24
+
25
+ def close
26
+ PCap.pcap_dump_close(@dumper)
27
+ end
28
+
29
+ def to_ptr
30
+ @dumper
31
+ end
32
+
33
+ def inspect
34
+ "#<#{self.class}: 0x#{@dumper.address.to_s(16)}>"
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ require 'ffi'
2
+
3
+ module FFI
4
+ module PCap
5
+ class ErrorBuffer < FFI::Buffer
6
+
7
+ # Size of the error buffers
8
+ SIZE = 256
9
+
10
+ #
11
+ # Creates a new ErrorBuffer object.
12
+ #
13
+ def initialize
14
+ super(SIZE)
15
+ end
16
+
17
+ #
18
+ # Returns the error message within the error buffer.
19
+ #
20
+ def to_s
21
+ get_string(SIZE)
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ module FFI
2
+ module PCap
3
+ class ReadError < RuntimeError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1 @@
1
+ require 'pcap/exceptions/read_error'
data/lib/pcap/ffi.rb ADDED
@@ -0,0 +1,78 @@
1
+ require 'pcap/typedefs'
2
+
3
+ require 'ffi'
4
+
5
+ module FFI
6
+ module PCap
7
+ extend FFI::Library
8
+
9
+ ffi_lib 'libpcap'
10
+
11
+ enum :pcap_direction, [
12
+ :pcap_d_inout,
13
+ :pcap_d_in,
14
+ :pcap_d_out
15
+ ]
16
+
17
+ callback :pcap_handler, [:pointer, :pointer, :pointer], :void
18
+
19
+ attach_function :pcap_lookupdev, [:pointer], :string
20
+ attach_function :pcap_lookupnet, [:string, :pointer, :pointer, :pointer], :int
21
+ attach_function :pcap_open_live, [:string, :int, :int, :int, :pointer], :pointer
22
+ attach_function :pcap_open_dead, [:int, :int], :pointer
23
+ attach_function :pcap_open_offline, [:string, :pointer], :pointer
24
+ attach_function :pcap_fopen_offline, [:pointer, :string], :pointer
25
+ attach_function :pcap_close, [:pointer], :void
26
+ attach_function :pcap_loop, [:pointer, :int, :pcap_handler, :pointer], :int
27
+ attach_function :pcap_dispatch, [:pointer, :int, :pcap_handler, :pointer], :int
28
+ attach_function :pcap_next, [:pointer, :pointer], :pointer
29
+ attach_function :pcap_next_ex, [:pointer, :pointer, :pointer], :int
30
+ attach_function :pcap_breakloop, [:pointer], :void
31
+ attach_function :pcap_stats, [:pointer, :pointer], :int
32
+ attach_function :pcap_setfilter, [:pointer, :pointer], :int
33
+ attach_function :pcap_setdirection, [:pointer, :pcap_direction], :int
34
+ attach_function :pcap_getnonblock, [:pointer, :pointer], :int
35
+ attach_function :pcap_setnonblock, [:pointer, :int, :pointer], :int
36
+ attach_function :pcap_perror, [:pointer, :string], :void
37
+ attach_function :pcap_inject, [:pointer, :pointer, :int], :int
38
+ attach_function :pcap_sendpacket, [:pointer, :pointer, :int], :int
39
+ attach_function :pcap_strerror, [:int], :string
40
+ attach_function :pcap_geterr, [:pointer], :string
41
+ attach_function :pcap_compile, [:pointer, :pointer, :string, :int, :bpf_uint32], :int
42
+ attach_function :pcap_compile_nopcap, [:int, :int, :pointer, :string, :int, :bpf_uint32], :int
43
+ attach_function :pcap_freecode, [:pointer], :void
44
+ attach_function :pcap_datalink, [:pointer], :int
45
+ attach_function :pcap_list_datalinks, [:pointer, :pointer], :int
46
+ attach_function :pcap_set_datalink, [:pointer, :int], :int
47
+ attach_function :pcap_datalink_name_to_val, [:string], :int
48
+ attach_function :pcap_datalink_val_to_name, [:int], :string
49
+ attach_function :pcap_datalink_val_to_description, [:int], :string
50
+ attach_function :pcap_snapshot, [:pointer], :int
51
+ attach_function :pcap_is_swapped, [:pointer], :int
52
+ attach_function :pcap_major_version, [:pointer], :int
53
+ attach_function :pcap_minor_version, [:pointer], :int
54
+
55
+ attach_function :pcap_file, [:pointer], :pointer
56
+ attach_function :pcap_fileno, [:pointer], :int
57
+
58
+ attach_function :pcap_dump_open, [:pointer, :string], :pointer
59
+ attach_function :pcap_dump_fopen, [:pointer, :pointer], :pointer
60
+ attach_function :pcap_dump_file, [:pointer], :pointer
61
+ attach_function :pcap_dump_ftell, [:pointer], :long
62
+ attach_function :pcap_dump_flush, [:pointer], :int
63
+ attach_function :pcap_dump_close, [:pointer], :void
64
+ attach_function :pcap_dump, [:pointer, :pointer, :pointer], :void
65
+
66
+ attach_function :pcap_findalldevs, [:pointer, :pointer], :int
67
+ attach_function :pcap_freealldevs, [:pointer], :void
68
+
69
+ attach_function :pcap_lib_version, [], :string
70
+
71
+ attach_function :bpf_filter, [:pointer, :pointer, :uint, :uint], :uint
72
+ attach_function :bpf_validate, [:pointer, :int], :int
73
+ attach_function :bpf_image, [:pointer, :int], :string
74
+ attach_function :bpf_dump, [:pointer, :int], :void
75
+
76
+ # TODO: WIN32/MSDOS/UN*X specific definitions
77
+ end
78
+ end
@@ -0,0 +1,17 @@
1
+ require 'pcap/typedefs'
2
+
3
+ require 'ffi/struct'
4
+
5
+ module FFI
6
+ module PCap
7
+ class FileHeader < FFI::Struct
8
+ layout :magic, :bpf_uint32,
9
+ :version_major, :ushort,
10
+ :version_minor, :ushort,
11
+ :thiszone, :bpf_int32,
12
+ :sigfigs, :bpf_uint32,
13
+ :snaplen, :bpf_uint32,
14
+ :linktype, :bpf_uint32
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,170 @@
1
+ require 'pcap/exceptions/read_error'
2
+ require 'pcap/ffi'
3
+ require 'pcap/error_buffer'
4
+ require 'pcap/data_link'
5
+ require 'pcap/packet_header'
6
+ require 'pcap/stat'
7
+
8
+ require 'ffi'
9
+
10
+ module FFI
11
+ module PCap
12
+ class Handler
13
+
14
+ include Enumerable
15
+
16
+ # Default snaplen
17
+ SNAPLEN = 65535
18
+
19
+ # Pointer to the pcap opaque type
20
+ attr_reader :pcap
21
+
22
+ # Number of packets to sniff
23
+ attr_accessor :count
24
+
25
+ def initialize(pcap,options={},&block)
26
+ @pcap = pcap
27
+ @closed = false
28
+
29
+ # Default is to infinitely loop over packets.
30
+ @count = (options[:count] || -1)
31
+
32
+ if options[:direction]
33
+ self.direction = options[:direction]
34
+ end
35
+
36
+ @callback_wrapper = Proc.new do |user,header,bytes|
37
+ if @callback
38
+ @callback.call(user,PacketHeader.new(header),bytes)
39
+ end
40
+ end
41
+
42
+ callback(&block)
43
+
44
+ trap('SIGINT') { self.close }
45
+ end
46
+
47
+ def datalink
48
+ DataLink.new(PCap.pcap_datalink(@pcap))
49
+ end
50
+
51
+ def callback(&block)
52
+ @callback = block
53
+ return @callback
54
+ end
55
+
56
+ def direction=(dir)
57
+ directions = PCap.enum_type(:pcap_direction)
58
+
59
+ return PCap.pcap_setdirection(@pcap,directions[:"pcap_d_#{dir}"])
60
+ end
61
+
62
+ def non_blocking=(mode)
63
+ errbuf = ErrorBuffer.new
64
+ mode = if mode
65
+ 1
66
+ else
67
+ 0
68
+ end
69
+
70
+ if PCap.pcap_setnonblock(@pcap,mode,errbuf) == -1
71
+ raise(RuntimeError,errbuf.to_s,caller)
72
+ end
73
+
74
+ return mode == 1
75
+ end
76
+
77
+ def non_blocking?
78
+ errbuf = ErrorBuffer.new
79
+ mode = PCap.pcap_getnonblock(@pcap,errbuf)
80
+
81
+ if mode == -1
82
+ raise(RuntimeError,errbuf.to_s,caller)
83
+ end
84
+
85
+ return mode == 1
86
+ end
87
+
88
+ def loop(data=nil,&block)
89
+ callback(&block) if block
90
+
91
+ PCap.pcap_loop(@pcap,@count,@callback_wrapper,data)
92
+ end
93
+
94
+ alias each loop
95
+
96
+ def dispatch(data=nil,&block)
97
+ callback(&block) if block
98
+
99
+ return PCap.pcap_dispatch(@pcap,@count,@callback_wrapper,data)
100
+ end
101
+
102
+ def next
103
+ header = PacketHeader.new
104
+ data = PCap.pcap_next(@pcap,header)
105
+
106
+ return [nil, nil] if data.null?
107
+ return [header, data]
108
+ end
109
+
110
+ def next_extra
111
+ header_ptr = MemoryPointer.new(:pointer)
112
+ data_ptr = MemoryPointer.new(:pointer)
113
+
114
+ case PCap.pcap_next_ex(@pcap,header_ptr,data_ptr)
115
+ when -1
116
+ raise(ReadError,"an error occurred while reading the packet",caller)
117
+ when -2
118
+ raise(ReadError,"the 'savefile' contains no more packets",caller)
119
+ end
120
+
121
+ return [header_ptr.get_pointer(0), data_ptr.get_pointer(0)]
122
+ end
123
+
124
+ def open_dump(path)
125
+ dump_ptr = PCap.pcap_dump_open(@pcap,File.expand_path(path))
126
+
127
+ if dump_ptr.null?
128
+ raise(RuntimeError,error,caller)
129
+ end
130
+
131
+ return Dumper.new(dump_ptr)
132
+ end
133
+
134
+ def stats
135
+ stats = Stat.new
136
+
137
+ PCap.pcap_stats(@pcap,stats)
138
+ return stats
139
+ end
140
+
141
+ def error
142
+ PCap.pcap_geterr(@pcap)
143
+ end
144
+
145
+ def stop
146
+ PCap.pcap_breakloop(@pcap)
147
+ end
148
+
149
+ def closed?
150
+ @closed == true
151
+ end
152
+
153
+ def close
154
+ unless @closed
155
+ @closed = true
156
+ PCap.pcap_close(@pcap)
157
+ end
158
+ end
159
+
160
+ def to_ptr
161
+ @pcap
162
+ end
163
+
164
+ def inspect
165
+ "#<#{self.class}: 0x#{@pcap.address.to_s(16)}>"
166
+ end
167
+
168
+ end
169
+ end
170
+ end
data/lib/pcap/if.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'pcap/typedefs'
2
+ require 'pcap/addr'
3
+
4
+ require 'ffi/struct'
5
+
6
+ module FFI
7
+ module PCap
8
+ class IF < FFI::Struct
9
+ # interface is loopback
10
+ LOOPBACK = 0x00000001
11
+
12
+ layout :next, :pointer,
13
+ :name, :string,
14
+ :description, :string,
15
+ :addresses, :pointer,
16
+ :flags, :bpf_uint32
17
+
18
+ def next
19
+ IF.new(self[:next])
20
+ end
21
+
22
+ def name
23
+ self[:name]
24
+ end
25
+
26
+ def addresses
27
+ Addr.new(self[:addresses])
28
+ end
29
+
30
+ def to_s
31
+ self[:name]
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ require 'pcap/typedefs'
2
+
3
+ require 'ffi'
4
+
5
+ module FFI
6
+ module PCap
7
+ class InAddr < FFI::Struct
8
+
9
+ layout :s_addr, :in_addr_t
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ require 'pcap/typedefs'
2
+ require 'pcap/time_val'
3
+
4
+ require 'ffi/struct'
5
+
6
+ module FFI
7
+ module PCap
8
+ class PacketHeader < FFI::Struct
9
+ layout :ts, TimeVal,
10
+ :caplen, :bpf_uint32,
11
+ :len, :bpf_uint32
12
+
13
+ def timestamp
14
+ self[:ts]
15
+ end
16
+
17
+ def captured
18
+ self[:caplen]
19
+ end
20
+
21
+ def length
22
+ self[:len]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ require 'pcap/packets/typedefs'
2
+ require 'pcap/packet'
3
+
4
+ require 'ffi'
5
+
6
+ module FFI
7
+ module PCap
8
+ module Packets
9
+ class Ethernet < FFI::Struct
10
+
11
+ include Packet
12
+
13
+ # Number of bytes for an ethernet address
14
+ ADDR_LEN = 6
15
+
16
+ # Size of an Ethernet header
17
+ SIZE = 14
18
+
19
+ layout :ether_dhost, [:uchar, ADDR_LEN],
20
+ :ether_shost, [:uchar, ADDR_LEN],
21
+ :ether_type, :ushort
22
+
23
+ #
24
+ # Returns the source MAC address.
25
+ #
26
+ def src_mac
27
+ self[:ether_shost]
28
+ end
29
+
30
+ #
31
+ # Returns the destination MAC address.
32
+ #
33
+ def dest_mac
34
+ self[:ether_dhost]
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end