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