caper 0.2.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 +9 -0
- data/History.rdoc +31 -0
- data/LICENSE.ffi-pcap +23 -0
- data/README.rdoc +55 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/examples/ipfw_divert.rb +45 -0
- data/examples/print_bytes.rb +17 -0
- data/examples/test_loop.rb +48 -0
- data/lib/caper.rb +40 -0
- data/lib/caper/addr.rb +19 -0
- data/lib/caper/bpf.rb +104 -0
- data/lib/caper/bsd.rb +96 -0
- data/lib/caper/capture_wrapper.rb +287 -0
- data/lib/caper/common_wrapper.rb +173 -0
- data/lib/caper/copy_handler.rb +36 -0
- data/lib/caper/crt.rb +13 -0
- data/lib/caper/data_link.rb +171 -0
- data/lib/caper/dead.rb +35 -0
- data/lib/caper/dumper.rb +53 -0
- data/lib/caper/error_buffer.rb +42 -0
- data/lib/caper/exceptions.rb +19 -0
- data/lib/caper/file_header.rb +24 -0
- data/lib/caper/in_addr.rb +7 -0
- data/lib/caper/interface.rb +27 -0
- data/lib/caper/live.rb +301 -0
- data/lib/caper/offline.rb +51 -0
- data/lib/caper/packet.rb +163 -0
- data/lib/caper/packet_header.rb +23 -0
- data/lib/caper/pcap.rb +250 -0
- data/lib/caper/stat.rb +56 -0
- data/lib/caper/time_val.rb +46 -0
- data/lib/caper/typedefs.rb +25 -0
- data/lib/caper/version.rb +4 -0
- data/spec/data_link_spec.rb +65 -0
- data/spec/dead_spec.rb +34 -0
- data/spec/dumps/http.pcap +0 -0
- data/spec/dumps/simple_tcp.pcap +0 -0
- data/spec/error_buffer_spec.rb +17 -0
- data/spec/file_header_spec.rb +28 -0
- data/spec/live_spec.rb +87 -0
- data/spec/offline_spec.rb +61 -0
- data/spec/packet_behaviors.rb +68 -0
- data/spec/packet_injection_spec.rb +38 -0
- data/spec/packet_spec.rb +111 -0
- data/spec/pcap_spec.rb +149 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/wrapper_behaviors.rb +110 -0
- data/tasks/rcov.rb +6 -0
- data/tasks/rdoc.rb +17 -0
- data/tasks/spec.rb +9 -0
- data/tasks/yard.rb +16 -0
- metadata +140 -0
data/.gitignore
ADDED
data/History.rdoc
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
=== 0.2.0 / 2010-04-22
|
2
|
+
* Renamed library to 'caper' using Caper as the ruby namespace instead of
|
3
|
+
FFI::PCap
|
4
|
+
* Fully branched as a separate project under the new caper name.
|
5
|
+
|
6
|
+
=== 0.1.4 / 2010-04-20
|
7
|
+
* Fixes and example for pcap dumper
|
8
|
+
|
9
|
+
=== 0.1.3 / 2010-03-05
|
10
|
+
* Minor fixes for ruby 1.9 compatability
|
11
|
+
|
12
|
+
=== 0.1.2 / 2010-01-03
|
13
|
+
|
14
|
+
* Branched from sophsec/ffi-pcap by emonti
|
15
|
+
* Using ffi_dry for common struct interface
|
16
|
+
* Redesigned the pcap-specific pcap_pkthdr struct.
|
17
|
+
* Dismantled all other network packet parsing code.
|
18
|
+
* 'Handlers' have been split out into type-specific 'Wrappers' by features.
|
19
|
+
* The namespace 'Handler' has been reused instead for pcap_handler abstraction
|
20
|
+
* Added filtering support and interfaces for compiling filters into bpf code.
|
21
|
+
* Added packet injection on Live pcap interfaces.
|
22
|
+
* Tackled some minor Jruby compatability issues.
|
23
|
+
* Lots of documentation added throughout with yardoc tags.
|
24
|
+
* Lots of misc namespace mods and such, and some general refactoring.
|
25
|
+
* Lots of other stuff I'm probably forgetting.
|
26
|
+
* specs all pass on OS X, Linux, and Win32(except 1 which is a known issue)
|
27
|
+
|
28
|
+
=== 0.1.0 / 2009-04-29
|
29
|
+
|
30
|
+
* Initial release. (sophsec/ffi-pcap)
|
31
|
+
|
data/LICENSE.ffi-pcap
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
The MIT License
|
3
|
+
|
4
|
+
Copyright (c) 2009-2010 Hal Brodigan
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
'Software'), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
20
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
21
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
22
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
23
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
= caper
|
2
|
+
|
3
|
+
* http://github.com/emonti/caper
|
4
|
+
* Eric Monti (esmonti at gmail dot com)
|
5
|
+
|
6
|
+
This started as a fork of ffi-pcap by postmodern but has diverged
|
7
|
+
significantly from its original version.
|
8
|
+
|
9
|
+
* http://github.com/sophsec/ffi-pcap/
|
10
|
+
* Postmodern (postmodern.mod3 at gmail.com)
|
11
|
+
|
12
|
+
== DESCRIPTION:
|
13
|
+
|
14
|
+
Ruby FFI bindings for libpcap.
|
15
|
+
|
16
|
+
== FEATURES:
|
17
|
+
|
18
|
+
== EXAMPLES:
|
19
|
+
|
20
|
+
== REQUIREMENTS:
|
21
|
+
|
22
|
+
* libpcap [http://www.tcpdump.org/]
|
23
|
+
* ffi >= 0.5.3 [http://github.com/ffi/ffi]
|
24
|
+
* ffi_dry [http://github.com/emonti/ffi_dry]
|
25
|
+
|
26
|
+
== INSTALL:
|
27
|
+
|
28
|
+
$ sudo gem install caper
|
29
|
+
|
30
|
+
== LICENSE:
|
31
|
+
|
32
|
+
(please see LICENSE.ffi-pcap for the original ffi-pcap license)
|
33
|
+
|
34
|
+
The MIT License
|
35
|
+
|
36
|
+
Copyright (c) 2010 Eric Monti
|
37
|
+
|
38
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
39
|
+
a copy of this software and associated documentation files (the
|
40
|
+
'Software'), to deal in the Software without restriction, including
|
41
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
42
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
43
|
+
permit persons to whom the Software is furnished to do so, subject to
|
44
|
+
the following conditions:
|
45
|
+
|
46
|
+
The above copyright notice and this permission notice shall be
|
47
|
+
included in all copies or substantial portions of the Software.
|
48
|
+
|
49
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
50
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
51
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
52
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
53
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
54
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
55
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
Dir["tasks/*.rb"].each {|rt| require rt }
|
5
|
+
require 'rake/clean'
|
6
|
+
require './lib/caper/version.rb'
|
7
|
+
|
8
|
+
# Generate a gem using jeweler
|
9
|
+
begin
|
10
|
+
require 'jeweler'
|
11
|
+
Jeweler::Tasks.new do |gemspec|
|
12
|
+
gemspec.rubyforge_project = 'caper'
|
13
|
+
gemspec.name = "caper"
|
14
|
+
gemspec.summary = "FFI bindings for libpcap"
|
15
|
+
gemspec.email = "postmodern.mod3@gmail.com"
|
16
|
+
gemspec.homepage = "http://github.com/postmodern/caper"
|
17
|
+
gemspec.description = "Bindings to sniff packets using the FFI interface in Ruby."
|
18
|
+
gemspec.authors = ["Postmodern, Dakrone", "Eric Monti"]
|
19
|
+
gemspec.add_dependency "ffi"
|
20
|
+
gemspec.add_dependency "ffi_dry", ">= 0.1.9"
|
21
|
+
end
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
24
|
+
end
|
25
|
+
|
26
|
+
# vim: syntax=Ruby
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# ipfw add tee 6666 tcp from 192.168.63.128 to any
|
3
|
+
# ipfw add tee 6666 tcp from any to 192.168.63.128
|
4
|
+
|
5
|
+
require 'caper'
|
6
|
+
require "socket"
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
unless Process::Sys.getuid == 0
|
10
|
+
$stderr.puts "Must run #{$0} as root."
|
11
|
+
exit!
|
12
|
+
end
|
13
|
+
|
14
|
+
IPPROTO_DIVERT = 254
|
15
|
+
|
16
|
+
outfile = ARGV.shift
|
17
|
+
#outfile = "test_#{$$}.pcap"
|
18
|
+
|
19
|
+
# create a dummy pcap handle for dumping
|
20
|
+
pcap = Caper.open_dead(:datalink => :raw)
|
21
|
+
pcap_dumper = pcap.open_dump(outfile)
|
22
|
+
|
23
|
+
begin
|
24
|
+
divert_sock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW, IPPROTO_DIVERT)
|
25
|
+
sockaddr = Socket.pack_sockaddr_in( 6666, '0.0.0.0' )
|
26
|
+
divert_sock.bind(sockaddr)
|
27
|
+
|
28
|
+
puts "ready and waiting...."
|
29
|
+
|
30
|
+
while IO.select([divert_sock], nil, nil)
|
31
|
+
data = divert_sock.recv(65535) # or MTU?
|
32
|
+
pp data
|
33
|
+
pcap_dumper.write_pkt( Caper::Packet.from_string(data) )
|
34
|
+
pcap_dumper.flush
|
35
|
+
end
|
36
|
+
rescue Errno::EPERM
|
37
|
+
$stderr.puts "Must run #{$0} as root."
|
38
|
+
exit!
|
39
|
+
ensure
|
40
|
+
puts "Closing socket."
|
41
|
+
divert_sock.close
|
42
|
+
puts "Closing pcap dumper."
|
43
|
+
pcap_dumper.close
|
44
|
+
pcap.close
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'caper'
|
5
|
+
|
6
|
+
pcap =
|
7
|
+
Caper::Live.new(:dev => 'en0',
|
8
|
+
:promisc => true,
|
9
|
+
:handler => Caper::Handler)
|
10
|
+
|
11
|
+
pcap.loop() do |this,pkt|
|
12
|
+
puts "#{pkt.time}:"
|
13
|
+
|
14
|
+
pkt.captured.times {|i| print ' %.2x' % pkt.body_ptr.get_uchar(i) }
|
15
|
+
putc "\n"
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'caper'
|
5
|
+
require 'rbkb/extends'
|
6
|
+
require 'ffi/packets'
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
include FFI
|
10
|
+
|
11
|
+
pcap =
|
12
|
+
Caper::Live.new( :dev => 'en0',
|
13
|
+
:promisc => true )
|
14
|
+
|
15
|
+
tblk = lambda do |this,pkt|
|
16
|
+
puts "#{pkt.time.asctime}:"
|
17
|
+
|
18
|
+
puts pkt.body.hexdump
|
19
|
+
putc "\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
wrap_blk = lambda do |id, phdr, buf|
|
23
|
+
tblk.call(pcap, Caper::Packet.new(phdr, buf))
|
24
|
+
end
|
25
|
+
#Caper.pcap_loop(pcap.pcap, 10, wrap_blk, nil)
|
26
|
+
puts "-"*70
|
27
|
+
|
28
|
+
pcap.loop(:count => 3, :handler => Caper::Handler.new, &tblk)
|
29
|
+
puts "-"*70
|
30
|
+
|
31
|
+
class Parser < Caper::Handler
|
32
|
+
def receive_pcap(*args)
|
33
|
+
pcap, pkt = super(*args)
|
34
|
+
p = pkt.body_ptr
|
35
|
+
parsed = []
|
36
|
+
eth = Packets::Eth::Hdr.new(p)
|
37
|
+
parsed << Packets::Eth::Hdr.new(p)
|
38
|
+
parsed << Packets::Ip::Hdr.new(p += eth.size) if eth.lookup_etype == "IP"
|
39
|
+
|
40
|
+
[pkt, parsed]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
pcap.loop(:count => 10, :parser => Parser) {|pkt, frames|
|
44
|
+
pp frames.map {|x| x.class}
|
45
|
+
pp({ frames[1].src => frames[1].dst })
|
46
|
+
}
|
47
|
+
|
48
|
+
|
data/lib/caper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
begin; require 'rubygems'; rescue LoadError; end
|
2
|
+
|
3
|
+
require 'ffi_dry'
|
4
|
+
|
5
|
+
module Caper
|
6
|
+
extend FFI::Library
|
7
|
+
|
8
|
+
begin
|
9
|
+
ffi_lib "wpcap"
|
10
|
+
rescue LoadError
|
11
|
+
ffi_lib "pcap"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'caper/crt'
|
16
|
+
|
17
|
+
require 'caper/version'
|
18
|
+
require 'caper/exceptions'
|
19
|
+
|
20
|
+
# FFI typedefs, pointer wrappers, and struct
|
21
|
+
require 'caper/typedefs'
|
22
|
+
require 'caper/bsd'
|
23
|
+
require 'caper/addr'
|
24
|
+
require 'caper/interface'
|
25
|
+
require 'caper/file_header'
|
26
|
+
require 'caper/time_val'
|
27
|
+
require 'caper/packet_header'
|
28
|
+
require 'caper/stat'
|
29
|
+
require 'caper/bpf'
|
30
|
+
require 'caper/dumper'
|
31
|
+
|
32
|
+
# Ruby FFI function bindings, sugar, and misc wrappers
|
33
|
+
require 'caper/error_buffer'
|
34
|
+
require 'caper/pcap'
|
35
|
+
require 'caper/data_link'
|
36
|
+
require 'caper/packet'
|
37
|
+
require 'caper/live'
|
38
|
+
require 'caper/offline'
|
39
|
+
require 'caper/dead'
|
40
|
+
|
data/lib/caper/addr.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module Caper
|
3
|
+
|
4
|
+
# Representation of an interface address.
|
5
|
+
#
|
6
|
+
# See pcap_addr struct in pcap.h
|
7
|
+
class Addr < FFI::Struct
|
8
|
+
include FFI::DRY::StructHelper
|
9
|
+
|
10
|
+
dsl_layout do
|
11
|
+
p_struct :next, ::Caper::Addr
|
12
|
+
p_struct :addr, ::Caper::SockAddr, :desc => 'address'
|
13
|
+
p_struct :netmask, ::Caper::SockAddr, :desc => 'netmask of the address'
|
14
|
+
p_struct :broadcast, ::Caper::SockAddr, :desc => 'broadcast for the address'
|
15
|
+
p_struct :dest_addr, ::Caper::SockAddr, :desc => 'p2p destination for address'
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/caper/bpf.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
|
2
|
+
module Caper
|
3
|
+
|
4
|
+
# Includes structures defined in pcap-bpf.h
|
5
|
+
|
6
|
+
# Berkeley Packet Filter instruction data structure.
|
7
|
+
#
|
8
|
+
# See bpf_insn struct in pcap-bpf.h
|
9
|
+
class BPFInstruction < FFI::Struct
|
10
|
+
include FFI::DRY::StructHelper
|
11
|
+
|
12
|
+
dsl_layout do
|
13
|
+
field :code, :ushort
|
14
|
+
field :jt, :uchar
|
15
|
+
field :jf, :uchar
|
16
|
+
field :k, :bpf_int32
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
# Structure for pcap_compile(), pcap_setfilter(), etc.
|
22
|
+
#
|
23
|
+
# See bpf_program struct in pcap-bpf.h
|
24
|
+
class BPFProgram < FFI::Struct
|
25
|
+
include FFI::DRY::StructHelper
|
26
|
+
|
27
|
+
dsl_layout do
|
28
|
+
field :bf_len, :uint
|
29
|
+
field :bf_insn, :pointer
|
30
|
+
end
|
31
|
+
|
32
|
+
def instructions
|
33
|
+
i = 0
|
34
|
+
sz = BPFInstruction.size()
|
35
|
+
Array.new(self.bf_len) do
|
36
|
+
ins = BPFInstruction.new( self[:bf_insn] + i )
|
37
|
+
i += sz
|
38
|
+
ins
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def free!
|
43
|
+
unless @closed
|
44
|
+
@freed = true
|
45
|
+
Caper.pcap_freecode(self)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def freed?
|
50
|
+
return @freed == true
|
51
|
+
end
|
52
|
+
|
53
|
+
# Compiles a bpf filter without a pcap device being open. Downside is
|
54
|
+
# no error messages are available, whereas they are when you use
|
55
|
+
# open_dead() and use compile() on the resulting Dead.
|
56
|
+
#
|
57
|
+
# @param [Hash] opts
|
58
|
+
# Additional options for compile
|
59
|
+
#
|
60
|
+
# @option opts [optional, DataLink, Integer, String, Symbol] :datalink
|
61
|
+
# DataLink layer type. The argument type will be resolved to a DataLink
|
62
|
+
# value if possible. Defaults to data-link layer type NULL.
|
63
|
+
#
|
64
|
+
# @option opts [optional, Integer] :snaplen
|
65
|
+
# The snapshot length for the filter. Defaults to SNAPLEN
|
66
|
+
#
|
67
|
+
# @option opts [optional, Integer] :optimize
|
68
|
+
# Optimization flag. 0 means don't optimize. Defaults to 1.
|
69
|
+
#
|
70
|
+
# @option opts [optional, Integer] :netmask
|
71
|
+
# A 32-bit number representing the IPv4 netmask of the network on which
|
72
|
+
# packets are being captured. It is only used when checking for IPv4
|
73
|
+
# broadcast addresses in the filter program. Default: 0 (unspecified
|
74
|
+
# netmask)
|
75
|
+
#
|
76
|
+
# @return [BPFProgram]
|
77
|
+
# If no errors occur, a compiled BPFProgram is returned.
|
78
|
+
#
|
79
|
+
def self.compile(expr, opts={})
|
80
|
+
datalink = (opts[:datalink] || 1)
|
81
|
+
dl = datalink.kind_of?(DataLink) ? datalink : DataLink.new(datalink)
|
82
|
+
slen = (opts[:snaplen] || DEFAULT_SNAPLEN)
|
83
|
+
optimize = (opts[:optimize] || 1)
|
84
|
+
mask = (opts[:netmask] || 0)
|
85
|
+
code = BPFProgram.new()
|
86
|
+
r = Caper.pcap_compile_nopcap(slen, dl.value, code, expr, optimize, mask)
|
87
|
+
raise(LibError, "pcap_compile_nopcap(): unspecified error") if r < 0
|
88
|
+
return code
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
attach_function :pcap_compile_nopcap, [:int, :int, BPFProgram, :string, :int, :bpf_uint32], :int
|
95
|
+
|
96
|
+
attach_function :bpf_filter, [BPFInstruction, :pointer, :uint, :uint], :uint
|
97
|
+
attach_function :bpf_validate, [BPFInstruction, :int], :int
|
98
|
+
attach_function :bpf_image, [BPFInstruction, :int], :string
|
99
|
+
attach_function :bpf_dump, [BPFProgram, :int], :void
|
100
|
+
attach_function :pcap_freecode, [BPFProgram], :void
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
|
data/lib/caper/bsd.rb
ADDED
@@ -0,0 +1,96 @@
|
|
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 Caper
|
8
|
+
typedef :uint8, :sa_family_t
|
9
|
+
typedef :uint32, :in_addr_t
|
10
|
+
typedef :uint16, :in_port_t
|
11
|
+
|
12
|
+
# contains AF_* constants culled from Ruby's ::Socket
|
13
|
+
module AF
|
14
|
+
include ::FFI::DRY::ConstMap
|
15
|
+
slurp_constants(::Socket, "AF_")
|
16
|
+
def self.list; @@list ||= super() ; end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Common abstract superclass for all sockaddr struct classes
|
20
|
+
#
|
21
|
+
class SockAddrFamily < ::FFI::Struct
|
22
|
+
include ::FFI::DRY::StructHelper
|
23
|
+
|
24
|
+
# returns an address family name for the :family struct member value
|
25
|
+
def lookup_family
|
26
|
+
AF[ self[:family] ]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# generic sockaddr, always good to have around
|
31
|
+
#
|
32
|
+
class SockAddr < SockAddrFamily
|
33
|
+
dsl_layout do
|
34
|
+
field :len, :uint8, :desc => 'total length of struct'
|
35
|
+
field :family, :sa_family_t, :desc => 'address family (AF_*)'
|
36
|
+
field :data, :char, :desc => 'variable length bound by :len'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# Used to represent a 32-bit IPv4 address in a sock_addr_in structure
|
42
|
+
#
|
43
|
+
class InAddr < ::FFI::Struct
|
44
|
+
include ::FFI::DRY::StructHelper
|
45
|
+
dsl_layout { field :in_addr, :in_addr_t, :desc => 'inet address' }
|
46
|
+
end
|
47
|
+
|
48
|
+
# sockaddr inet, always good to have around
|
49
|
+
#
|
50
|
+
class SockAddrIn < SockAddrFamily
|
51
|
+
dsl_layout do
|
52
|
+
field :len, :uint8, :desc => 'length of structure (16)'
|
53
|
+
field :family, :sa_family_t, :desc => 'address family (AF_INET)'
|
54
|
+
field :port, :in_port_t, :desc => '16-bit TCP or UDP port number'
|
55
|
+
field :addr, :in_addr_t, :desc => '32-bit IPv4 address'
|
56
|
+
array :_sa_zero, [:uint8,8], :desc => 'unused'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Used to represent an IPv6 address in a sock_addr_in6 structure
|
61
|
+
#
|
62
|
+
class In6Addr < ::FFI::Struct
|
63
|
+
include ::FFI::DRY::StructHelper
|
64
|
+
dsl_layout { array :s6_addr, [:uint8, 16], :desc => 'IPv6 address' }
|
65
|
+
end
|
66
|
+
|
67
|
+
# IPv6 socket address
|
68
|
+
#
|
69
|
+
class SockAddrIn6 < SockAddrFamily
|
70
|
+
dsl_layout do
|
71
|
+
field :len, :uint8, :desc => 'length of structure(24)'
|
72
|
+
field :family, :sa_family_t, :desc => 'address family (AF_INET6)'
|
73
|
+
field :port, :in_port_t, :desc => 'transport layer port'
|
74
|
+
field :flowinfo, :uint32, :desc => 'priority & flow label'
|
75
|
+
struct :addr, ::Caper::In6Addr, :desc => 'IPv6 address'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
# data-link socket address
|
81
|
+
#
|
82
|
+
class SockAddrDl < SockAddrFamily
|
83
|
+
dsl_layout do
|
84
|
+
field :len, :uint8, :desc => 'length of structure(variable)'
|
85
|
+
field :family, :sa_family_t, :desc => 'address family (AF_LINK)'
|
86
|
+
field :sdl_index, :uint16, :desc => 'system assigned index, if > 0'
|
87
|
+
field :dltype, :uint8, :desc => 'IFT_ETHER, etc. from net/if_types.h'
|
88
|
+
field :nlen, :uint8, :desc => 'name length, from :_data'
|
89
|
+
field :alen, :uint8, :desc => 'link-layer addres-length'
|
90
|
+
field :slen, :uint8, :desc => 'link-layer selector length'
|
91
|
+
field :_data, :char, :desc => 'minimum work area=12, can be larger'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|