dnet-ffi 0.1.3
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/.document +5 -0
- data/.gitignore +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +37 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/dnet-ffi.gemspec +99 -0
- data/lib/dnet.rb +35 -0
- data/lib/dnet/addr.rb +204 -0
- data/lib/dnet/arp.rb +168 -0
- data/lib/dnet/blob.rb +246 -0
- data/lib/dnet/bsd.rb +123 -0
- data/lib/dnet/constants.rb +555 -0
- data/lib/dnet/eth.rb +143 -0
- data/lib/dnet/fw.rb +106 -0
- data/lib/dnet/helpers.rb +164 -0
- data/lib/dnet/icmp.rb +304 -0
- data/lib/dnet/intf.rb +194 -0
- data/lib/dnet/ip.rb +315 -0
- data/lib/dnet/ip6.rb +59 -0
- data/lib/dnet/rand.rb +33 -0
- data/lib/dnet/route.rb +103 -0
- data/lib/dnet/tcp.rb +103 -0
- data/lib/dnet/tun.rb +24 -0
- data/lib/dnet/typedefs.rb +12 -0
- data/lib/dnet/udp.rb +31 -0
- data/lib/dnet/util.rb +70 -0
- data/samples/eth_send_raw.rb +29 -0
- data/samples/ifconfig-alike.rb +44 -0
- data/samples/udp_send_raw.rb +74 -0
- data/spec/addr_spec.rb +15 -0
- data/spec/arp_spec.rb +95 -0
- data/spec/blob_spec.rb +15 -0
- data/spec/bsd_spec.rb +60 -0
- data/spec/dnet-ffi_spec.rb +31 -0
- data/spec/eth_spec.rb +47 -0
- data/spec/fw_spec.rb +15 -0
- data/spec/intf_spec.rb +98 -0
- data/spec/ip6_spec.rb +15 -0
- data/spec/ip_spec.rb +15 -0
- data/spec/rand_spec.rb +15 -0
- data/spec/route_spec.rb +94 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/tun_spec.rb +15 -0
- metadata +121 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin ; require 'rubygems'; rescue LoadError ; end
|
4
|
+
require 'dnet'
|
5
|
+
include Dnet
|
6
|
+
|
7
|
+
unless dev=ARGV.shift
|
8
|
+
STDERR.puts "Usage: #{File.basename $0} interface"
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
|
12
|
+
STDERR.puts "Input data via stdin:"
|
13
|
+
data = STDIN.read
|
14
|
+
|
15
|
+
begin
|
16
|
+
sent = Eth::Handle.open(dev) {|h| h.eth_send(data) }
|
17
|
+
rescue Exception => e
|
18
|
+
STDERR.puts "Error: <#{e.class}> - #{e}"
|
19
|
+
STDERR.puts " ** try running as root?" if e.is_a? Dnet::HandleError
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
|
23
|
+
if sent == data.size
|
24
|
+
puts "Sent: #{sent} bytes"
|
25
|
+
exit 0
|
26
|
+
else
|
27
|
+
STDERR.puts "Error: expected #{data.size} sent bytes - got #{sent}"
|
28
|
+
exit 1
|
29
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin; require 'rubygems' ; rescue LoadError; end
|
4
|
+
require 'dnet'
|
5
|
+
|
6
|
+
@arg_if = ARGV.shift
|
7
|
+
|
8
|
+
module Dumper
|
9
|
+
def self.dump_if_inet(a)
|
10
|
+
return "#{a.lookup_atype} address: #{a.string} net: #{a.net.string} "+
|
11
|
+
"bcast: #{a.bcast.string}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.dump_if_inet6(a)
|
15
|
+
return "#{a.lookup_atype} address: #{a.string} net: #{a.net.string} "
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.dump_if_link(a)
|
19
|
+
return "#{a.lookup_atype} address: #{a.string}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Dnet::IntfHandle.each_entry do |entry|
|
24
|
+
next if @arg_if and entry.if_name != @arg_if
|
25
|
+
|
26
|
+
puts("#{entry.if_name}: "+
|
27
|
+
"type=#{entry.lookup_itype.downcase} "+
|
28
|
+
"flags=#{entry.flags}<#{entry.lookup_flags.join(',')}> "+
|
29
|
+
"mtu #{entry.mtu}\n" )
|
30
|
+
|
31
|
+
[:if_addr, :link_addr, :dst_addr].each do |addr_field|
|
32
|
+
addr = entry.send(addr_field)
|
33
|
+
if kind=addr.lookup_atype
|
34
|
+
puts " " + Dumper.__send__(:"dump_if_#{kind}", addr)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
entry.aliases.each do |alias_addr|
|
39
|
+
if kind = alias_addr.lookup_atype
|
40
|
+
puts " alias: " + Dumper.__send__(:"dump_if_#{kind}", alias_addr)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# A basic IP/UDP spoofing example using dnet-ffi libdnet ruby bindings.
|
3
|
+
#
|
4
|
+
# Usage: udp_send_raw.rb src-addr:sport dst-addr:dport [msg]
|
5
|
+
#
|
6
|
+
# Specify the contents for the udp message as 'msg', or via STDIN if no
|
7
|
+
# msg is supplied on the commandline.
|
8
|
+
|
9
|
+
begin ; require 'rubygems' ; rescue LoadError; end
|
10
|
+
require 'dnet'
|
11
|
+
|
12
|
+
include Dnet
|
13
|
+
|
14
|
+
arg_rx = %r{^(#{Util::RX_IP4_ADDR}):(\d+)$}
|
15
|
+
begin
|
16
|
+
src_arg = ARGV.shift or raise "wrong arguments"
|
17
|
+
dst_arg = ARGV.shift or raise "wrong arguments"
|
18
|
+
raise "Invalid src addr" unless src_arg and sm=arg_rx.match(src_arg)
|
19
|
+
raise "Invalid dst addr" unless dst_arg and dm=arg_rx.match(dst_arg)
|
20
|
+
src = sm[1]
|
21
|
+
sport = sm[2].to_i
|
22
|
+
dst = dm[1]
|
23
|
+
dport = dm[2].to_i
|
24
|
+
rescue
|
25
|
+
STDERR.puts "Error: #{$!}"
|
26
|
+
STDERR.puts "Usage: #{File.basename $0} src-addr:sport dst-addr:dport [msg]"
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
|
30
|
+
data=(ARGV.shift || STDIN.read)
|
31
|
+
|
32
|
+
blob = Blob.new
|
33
|
+
|
34
|
+
udp_sz = Udp::Hdr.size + data.size
|
35
|
+
tot_sz = Ip::Hdr.size + udp_sz
|
36
|
+
|
37
|
+
|
38
|
+
ip_hdr = Ip::Hdr.new :tos => 0,
|
39
|
+
:len => tot_sz,
|
40
|
+
:off => 0,
|
41
|
+
:ttl => 128,
|
42
|
+
:proto => Ip::Proto::UDP,
|
43
|
+
:src => src,
|
44
|
+
:dst => dst
|
45
|
+
|
46
|
+
blob.write(ip_hdr.to_ptr, Ip::Hdr.size)
|
47
|
+
|
48
|
+
udp_hdr = Udp::Hdr.new :sport => sport,
|
49
|
+
:dport => dport,
|
50
|
+
:len => udp_sz
|
51
|
+
|
52
|
+
blob.write(udp_hdr.to_ptr, Udp::Hdr.size)
|
53
|
+
|
54
|
+
blob.write(data)
|
55
|
+
|
56
|
+
begin
|
57
|
+
blob.rewind
|
58
|
+
sent = Ip::Handle.open { |h| h.ip_send(blob.read) }
|
59
|
+
|
60
|
+
if sent != tot_sz
|
61
|
+
raise "expected #{tot_sz} bytes sent, but got #{sent}"
|
62
|
+
else
|
63
|
+
STDERR.puts "Sent: #{sent} bytes"
|
64
|
+
end
|
65
|
+
rescue Exception => e
|
66
|
+
STDERR.puts "Error: <#{e.class}> - #{e}"
|
67
|
+
STDERR.puts " ** try running as root?" if e.is_a? Dnet::HandleError
|
68
|
+
exit 1
|
69
|
+
ensure
|
70
|
+
blob.release
|
71
|
+
blob=nil
|
72
|
+
end
|
73
|
+
|
74
|
+
exit 0
|
data/spec/addr_spec.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Dnet::Addr" do
|
4
|
+
context "dnet(3) addr_* function bindings" do
|
5
|
+
funcs = %w{addr_cmp addr_bcast addr_net addr_ntop addr_pton addr_ntoa addr_aton addr_ntos addr_ston addr_btos addr_stob addr_btom addr_mtob}
|
6
|
+
|
7
|
+
funcs.each do |func|
|
8
|
+
it "should have bound: #{func}()" do
|
9
|
+
::Dnet.respond_to?(func).should == true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/spec/arp_spec.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Dnet::Arp" do
|
4
|
+
context "dnet(3) arp_* function bindings" do
|
5
|
+
funcs = %w{ arp_open arp_add arp_delete arp_get arp_loop arp_close }
|
6
|
+
|
7
|
+
funcs.each do |func|
|
8
|
+
it "should have bound: #{func}()" do
|
9
|
+
::Dnet.respond_to?(func).should == true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
context "the Dnet::Arp module" do
|
16
|
+
it "should be a module" do
|
17
|
+
Arp.kind_of?(Module).should == true
|
18
|
+
end
|
19
|
+
|
20
|
+
[:open, :each_entry, :entries].each do |meth|
|
21
|
+
it "should provide a method called #{meth}()" do
|
22
|
+
Arp.respond_to?(meth).should == true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "the each_entry() method" do
|
27
|
+
it "should fire a block for each entry" do
|
28
|
+
i=0
|
29
|
+
Arp.each_entry {|e| i+=1 }
|
30
|
+
i.should_not == 0
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should yield arp entries to a block as Arp::Entry objects" do
|
34
|
+
Arp.each_entry {|e| e.kind_of?(Arp::Entry).should == true }
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
context "the entries() method" do
|
40
|
+
before(:all) do
|
41
|
+
@entries = Arp.entries()
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return an array" do
|
45
|
+
@entries.kind_of?(Array).should == true
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should produce a non-emtpy list" do
|
49
|
+
@entries.empty?.should == false
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should produce arp entries as Arp::Entry objects" do
|
53
|
+
@entries.each {|e| e.kind_of?(Arp::Entry).should == true }
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
context "the Dnet::Arp::Handle class" do
|
61
|
+
context "instance" do
|
62
|
+
before(:all) do
|
63
|
+
@h = Arp::Handle.new
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should have opened a handle" do
|
67
|
+
@h.handle.kind_of?(::FFI::Pointer).should == true
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should provide a way to get a list of entries" do
|
71
|
+
@h.respond_to?(:entries).should == true
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should provide that list as an array" do
|
75
|
+
@h.entries().kind_of?(Array).should == true
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should provide arp entries in that array" do
|
79
|
+
@h.entries().each{|e| e.kind_of?(Arp::Entry).should == true}
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should provide an iterator for entries" do
|
83
|
+
@h.respond_to?(:loop).should == true
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should provide arp entries through the iterator" do
|
87
|
+
@h.loop {|x| x.kind_of?(Arp::Entry).should == true }
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
end
|
data/spec/blob_spec.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Dnet::Blob" do
|
4
|
+
context "dnet(3) blob_* function bindings" do
|
5
|
+
funcs = %w{ blob_new blob_read blob_write blob_seek blob_index blob_rindex blob_pack blob_unpack blob_print blob_free }
|
6
|
+
|
7
|
+
funcs.each do |func|
|
8
|
+
it "should have bound: #{func}()" do
|
9
|
+
::Dnet.respond_to?(func).should == true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/spec/bsd_spec.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Dnet::AF" do
|
4
|
+
context "address family lookups" do
|
5
|
+
it "should map constants for address families" do
|
6
|
+
Dnet::AF.const_get("LINK").should == Socket::AF_LINK
|
7
|
+
Dnet::AF.const_get("INET").should == Socket::AF_INET
|
8
|
+
Dnet::AF.const_get("INET6").should == Socket::AF_INET6
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should identify socket addr family names by number" do
|
12
|
+
Dnet::AF[ Socket::AF_LINK ].should == "LINK"
|
13
|
+
Dnet::AF[ Socket::AF_INET ].should == "INET"
|
14
|
+
Dnet::AF[ Socket::AF_INET6 ].should == "INET6"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should identify socket addr numbers by string name" do
|
18
|
+
Dnet::AF[ "LINK" ].should == Socket::AF_LINK
|
19
|
+
Dnet::AF[ "INET" ].should == Socket::AF_INET
|
20
|
+
Dnet::AF[ "INET6" ].should == Socket::AF_INET6
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should identify socket addr numbers by symbol name" do
|
24
|
+
Dnet::AF[ :link ].should == Socket::AF_LINK
|
25
|
+
Dnet::AF[ :inet ].should == Socket::AF_INET
|
26
|
+
Dnet::AF[ :inet6 ].should == Socket::AF_INET6
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "SockAddrIn" do
|
33
|
+
context "from Socket::pack_sockaddr_in / to unpack_sockaddr_in" do
|
34
|
+
before(:all) do
|
35
|
+
@raw= ::Socket.pack_sockaddr_in(9999, "127.0.0.1")
|
36
|
+
@sa = ::Dnet::SockAddrIn.new :raw => @raw
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should capture a packed sockaddr_in" do
|
40
|
+
@sa.to_ptr.read_string(@sa.size).should == @raw
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should return the correct family value family()" do
|
44
|
+
@sa.family.should == ::Socket::AF_INET
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should return the correct family name with lookup_family()" do
|
48
|
+
@sa.lookup_family.should == "INET"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return 8 bytes of null data starting at :_sa_zero" do
|
52
|
+
(@sa.to_ptr + @sa.offset_of(:_sa_zero)).read_string(8).should == "\x00"*8
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should unpack to the correct address" do
|
56
|
+
(::Socket.unpack_sockaddr_in(@sa.to_ptr.read_string(@sa.size))).should == [9999, "127.0.0.1"]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Dnet" do
|
4
|
+
context "assert..." do
|
5
|
+
# ...
|
6
|
+
end
|
7
|
+
context "Utilities" do
|
8
|
+
[:htonl, :htons, :ntohl, :ntohs].each do |func|
|
9
|
+
it "should have bound the utility C function #{func}()" do
|
10
|
+
Dnet::Util.respond_to?(func).should == true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "long functions" do
|
15
|
+
[:htonl, :ntohl].each do |func|
|
16
|
+
it "should accept and return 32-bit numbers with #{func}()" do
|
17
|
+
Dnet.__send__(func, 0xffffffff).should == 0xffffffff
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "short functions" do
|
23
|
+
[:htons, :ntohs].each do |func|
|
24
|
+
it "should accept and return 16-bit numbers with #{func}()" do
|
25
|
+
Dnet.__send__(func, 0xffff).should == 0xffff
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
data/spec/eth_spec.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Dnet::Eth" do
|
4
|
+
|
5
|
+
context "dnet(3) function bindings" do
|
6
|
+
funcs = %w{ eth_open eth_get eth_set eth_send eth_close }
|
7
|
+
|
8
|
+
funcs.each do |func|
|
9
|
+
it "should have bound: #{func}()" do
|
10
|
+
::Dnet.respond_to?(func).should == true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
context "the Dnet::Eth module" do
|
17
|
+
it "should be a module" do
|
18
|
+
Eth.kind_of?(Module).should == true
|
19
|
+
end
|
20
|
+
|
21
|
+
[:open, :eth_send].each do |meth|
|
22
|
+
it "should provide a method called #{meth}()" do
|
23
|
+
Eth.respond_to?(meth).should == true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "the Eth::Handle class" do
|
29
|
+
context "instance" do
|
30
|
+
before(:all) do
|
31
|
+
raise "!!! need an env. variable DNET_TEST_INTERFACE" unless NET_DEV
|
32
|
+
begin
|
33
|
+
@h = Eth::Handle.new(NET_DEV)
|
34
|
+
rescue HandleError
|
35
|
+
raise "!!! You may need to be root to run this test -- #{$!}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have opened a handle" do
|
40
|
+
@h.handle.kind_of?(::FFI::Pointer).should == true
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/spec/fw_spec.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Dnet::Fw" do
|
4
|
+
context "dnet(3) fw_* function bindings" do
|
5
|
+
funcs = %w{ fw_open fw_add fw_delete fw_loop fw_close }
|
6
|
+
|
7
|
+
funcs.each do |func|
|
8
|
+
it "should have bound: #{func}()" do
|
9
|
+
::Dnet.respond_to?(func).should == true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/spec/intf_spec.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Dnet::Intf" do
|
4
|
+
|
5
|
+
context "dnet(3) intf_* function bindings" do
|
6
|
+
funcs = %w{ intf_open intf_get intf_get_src intf_get_dst intf_set intf_loop intf_close }
|
7
|
+
|
8
|
+
funcs.each do |func|
|
9
|
+
it "should have bound: #{func}()" do
|
10
|
+
respond_to?(func).should == true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
context "the Dnet::Intf module" do
|
17
|
+
it "should be a module" do
|
18
|
+
Intf.kind_of?(Module).should == true
|
19
|
+
end
|
20
|
+
|
21
|
+
[:open, :each_entry, :entries].each do |meth|
|
22
|
+
it "should provide a method called #{meth}()" do
|
23
|
+
Intf.respond_to?(meth).should == true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "the each_entry() method" do
|
28
|
+
it "should fire a block for each entry" do
|
29
|
+
i=0
|
30
|
+
Intf.each_entry {|e| i+=1 }
|
31
|
+
i.should_not == 0
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should yield interface entries to a block as Intf::Entry objects" do
|
35
|
+
Intf.each_entry {|e| e.kind_of?(Intf::Entry).should == true }
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
context "the entries() method" do
|
41
|
+
before(:all) do
|
42
|
+
@entries = Intf.entries()
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return an array of entries" do
|
46
|
+
@entries.kind_of?(Array).should == true
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should produce a non-emtpy entries list" do
|
50
|
+
@entries.empty?.should == false
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should produce entries containing interface entries" do
|
54
|
+
@entries.each {|e| e.kind_of?(Intf::Entry).should == true }
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should produce entries with interface name strings" do
|
58
|
+
@entries.each {|e| e.if_name.kind_of?(String).should == true }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
context "the Intf::Handle class" do
|
65
|
+
context "instance" do
|
66
|
+
before(:all) do
|
67
|
+
@intf_h = Intf::Handle.new
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should have opened a handle" do
|
71
|
+
@intf_h.handle.kind_of?(::FFI::Pointer).should == true
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should provide a way to get a list entries" do
|
75
|
+
@intf_h.respond_to?(:entries).should == true
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should provide that list as an array" do
|
79
|
+
@intf_h.entries().kind_of?(Array).should == true
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should provide interface entries in that array" do
|
83
|
+
@intf_h.entries().each{|e| e.kind_of?(Intf::Entry).should == true}
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should provide an iterator for entries" do
|
87
|
+
@intf_h.respond_to?(:loop).should == true
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should provide an interface entry through the iterator" do
|
91
|
+
@intf_h.loop {|x| x.kind_of?(Intf::Entry).should == true }
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|