emonti-dnet-ffi 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/dnet-ffi.gemspec +4 -2
- data/lib/dnet/addr.rb +5 -2
- data/lib/dnet/eth.rb +29 -6
- data/lib/dnet/intf.rb +1 -1
- data/lib/dnet/ip.rb +25 -0
- data/lib/dnet/util.rb +2 -1
- data/samples/eth_send_raw.rb +29 -0
- data/samples/ifconfig-alike.rb +44 -0
- data/samples/udp_send_raw.rb +8 -12
- metadata +6 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.3
|
data/dnet-ffi.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{dnet-ffi}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Eric Monti"]
|
12
|
-
s.date = %q{2009-09-
|
12
|
+
s.date = %q{2009-09-17}
|
13
13
|
s.description = %q{Ruby FFI bindings for the libdnet raw network library}
|
14
14
|
s.email = %q{emonti@matasano.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -44,6 +44,8 @@ Gem::Specification.new do |s|
|
|
44
44
|
"lib/dnet/typedefs.rb",
|
45
45
|
"lib/dnet/udp.rb",
|
46
46
|
"lib/dnet/util.rb",
|
47
|
+
"samples/eth_send_raw.rb",
|
48
|
+
"samples/ifconfig-alike.rb",
|
47
49
|
"samples/udp_send_raw.rb",
|
48
50
|
"spec/addr_spec.rb",
|
49
51
|
"spec/arp_spec.rb",
|
data/lib/dnet/addr.rb
CHANGED
@@ -23,7 +23,8 @@ module Dnet
|
|
23
23
|
class Addr < ::FFI::Struct
|
24
24
|
include ::FFI::DRY::StructHelper
|
25
25
|
|
26
|
-
|
26
|
+
# A mapping of dnet address types
|
27
|
+
ADDR_TYPES = [ nil, :link, :inet, :inet6 ]
|
27
28
|
|
28
29
|
# struct addr { ... };
|
29
30
|
dsl_layout do
|
@@ -53,7 +54,8 @@ module Dnet
|
|
53
54
|
# leaves setting :bits up to chance depending on which hash key gets
|
54
55
|
# plucked first in set_fields() because of how ip_aton() works under
|
55
56
|
# the hood.
|
56
|
-
def set_fields(params)
|
57
|
+
def set_fields(params=nil)
|
58
|
+
params ||= {}
|
57
59
|
if params[:bits] and params[:addr]
|
58
60
|
raise( ::ArgumentError,
|
59
61
|
"Don't use :addr and :bits fields together. "+
|
@@ -66,6 +68,7 @@ module Dnet
|
|
66
68
|
# Looks up this object's 'atype' member against ADDR_TYPES
|
67
69
|
# Returns a symbol for the type or nil a type is not found.
|
68
70
|
def addr_type; ADDR_TYPES[ self[:atype] ] ; end
|
71
|
+
alias lookup_atype addr_type
|
69
72
|
|
70
73
|
# Returns a human-readable network address from self. Uses dnet(3)'s
|
71
74
|
# addr_ntoa function under the hood.
|
data/lib/dnet/eth.rb
CHANGED
@@ -9,21 +9,26 @@ module Dnet
|
|
9
9
|
# struct eth_addr { ... } eth_addr_t;
|
10
10
|
dsl_layout{ array :data, [:uchar, ETH_ADDR_LEN] }
|
11
11
|
|
12
|
-
MAC_RX = /^[a-f0-9]{1,2}([:-]?)(?:[a-f0-9]{1,2}\1){4}[a-f0-9]{1,2}$/i
|
13
|
-
|
14
12
|
# Adds the ability to initialize a new EthAddr with a mac address
|
15
13
|
# string such as 'de:ad:be:ef:ba:be'. This argument is only parsed
|
16
14
|
# if it is passed as the only String argument.
|
17
15
|
def initialize(*args)
|
18
16
|
if args.size == 1 and (s=args[0]).is_a? String
|
19
|
-
|
20
|
-
|
21
|
-
super(::FFI::MemoryPointer.from_string(raw))
|
17
|
+
super()
|
18
|
+
self.addr = s
|
22
19
|
else
|
23
20
|
super(*args)
|
24
21
|
end
|
25
22
|
end
|
26
23
|
|
24
|
+
def addr=(val)
|
25
|
+
unless val.to_s =~ /^#{Dnet::Util::RX_MAC_ADDR}$/
|
26
|
+
raise(ArgumentError, "invalid mac address #{val.inspect}")
|
27
|
+
end
|
28
|
+
raw = ::Dnet::Util.unhexify(val, /[:-]/)
|
29
|
+
self[:data].to_ptr.write_string(raw, ETH_ADDR_LEN)
|
30
|
+
end
|
31
|
+
|
27
32
|
# Returns the MAC address as an array of unsigned char values.
|
28
33
|
def chars; self[:data].to_a ; end
|
29
34
|
|
@@ -42,13 +47,31 @@ module Dnet
|
|
42
47
|
include ::FFI::DRY::StructHelper
|
43
48
|
include ::Dnet::NetEndianHelper
|
44
49
|
|
50
|
+
module Etype
|
51
|
+
include ::FFI::DRY::ConstMap
|
52
|
+
slurp_constants ::Dnet, "ETH_TYPE_"
|
53
|
+
def list; @@list ||= super(); end
|
54
|
+
end
|
55
|
+
|
45
56
|
dsl_layout do
|
46
57
|
struct :dst, EthAddr, :desc => 'destination address'
|
47
58
|
struct :src, EthAddr, :desc => 'source address'
|
48
59
|
field :etype, :ushort, :desc => 'ethernet payload type'
|
49
60
|
end
|
50
|
-
end
|
51
61
|
|
62
|
+
def lookup_etype
|
63
|
+
Etype[ self.etype ]
|
64
|
+
end
|
65
|
+
|
66
|
+
alias _divert_set_eth etype=
|
67
|
+
|
68
|
+
def etype=(val)
|
69
|
+
if val.kind_of? String or val.kind_of? Symbol
|
70
|
+
val = Etype[ val ] or raise(ArgumentError, "invalid eth type #{val}")
|
71
|
+
end
|
72
|
+
_divert_set_eth(val)
|
73
|
+
end
|
74
|
+
end
|
52
75
|
|
53
76
|
# Obtains a new handle to transmit raw Ethernet frames via the specified
|
54
77
|
# network device.
|
data/lib/dnet/intf.rb
CHANGED
data/lib/dnet/ip.rb
CHANGED
@@ -46,11 +46,36 @@ module Dnet
|
|
46
46
|
field :dst, :uint32, :desc => 'destination address'
|
47
47
|
end
|
48
48
|
|
49
|
+
# Overrides set_fields to supply a default value for the 'v_hl' field.
|
50
|
+
#
|
51
|
+
# v = 4
|
52
|
+
# hl = 5 # number of 32-bit words - 20 bytes (size of hdr without opts)
|
53
|
+
#
|
49
54
|
def set_fields(params=nil)
|
50
55
|
params ||= {}
|
51
56
|
super({:v_hl => 0x45}.merge(params))
|
52
57
|
end
|
53
58
|
|
59
|
+
# Sets the value of the hl field. This field is a 4-bit value occupying
|
60
|
+
# the lower 4 bits of the 'v_hl' field.
|
61
|
+
#
|
62
|
+
# This value is the size of the IP header (including opts if present)
|
63
|
+
# in 32-bit words. The byte size maximum is 15*4 - 60 bytes.
|
64
|
+
def hl=(val)
|
65
|
+
raise(ArgumentError, "value for header length too high") if val > 0xf
|
66
|
+
self[:v_hl] &= 0xf0
|
67
|
+
self[:v_hl] += val
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns the value of the hl field. This field is a 4-bit value occupying
|
71
|
+
# the lower 4 bits of the 'v_hl' field.
|
72
|
+
#
|
73
|
+
# This value is the size of the IP header (including opts if present)
|
74
|
+
# in 32-bit words. The byte size maximum is 15*4 - 60 bytes.
|
75
|
+
def hl
|
76
|
+
self[:v_hl] & 0x0f
|
77
|
+
end
|
78
|
+
|
54
79
|
# Type of service (ip_tos), RFC 1349 ("obsoleted by RFC 2474")
|
55
80
|
#
|
56
81
|
# Contains mappings for all the IP_TOS_[A-Z].* flags constants
|
data/lib/dnet/util.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
module Dnet
|
3
3
|
module Util
|
4
4
|
RX_IP4_ADDR = /(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/
|
5
|
+
RX_MAC_ADDR = /(?:(?:[a-f0-9]{1,2}[:-])?{5}[a-f0-9]{1,2})/i
|
5
6
|
|
6
7
|
# A number of helper methods which can be used to extend class, instance,
|
7
8
|
# or module
|
@@ -39,7 +40,7 @@ module Dnet
|
|
39
40
|
|
40
41
|
# takes a IPv4 number and returns it as a 32-bit number
|
41
42
|
def ipv4_atol(str)
|
42
|
-
unless str =~ /^#{RX_IP4_ADDR}$/
|
43
|
+
unless str =~ /^#{::Dnet::Util::RX_IP4_ADDR}$/
|
43
44
|
raise(::ArgumentError, "invalid IP address #{str.inspect}")
|
44
45
|
else
|
45
46
|
u32=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
|
+
|
data/samples/udp_send_raw.rb
CHANGED
@@ -54,21 +54,17 @@ blob.write(udp_hdr.to_ptr, Udp::Hdr.size)
|
|
54
54
|
blob.write(data)
|
55
55
|
|
56
56
|
begin
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
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"
|
65
64
|
end
|
66
|
-
rescue ::Dnet::HandleError => e
|
67
|
-
STDERR.puts "Error: <#{e.class}> - #{e}"
|
68
|
-
STDERR.puts " ** try running as root?"
|
69
|
-
exit 1
|
70
65
|
rescue Exception => e
|
71
66
|
STDERR.puts "Error: <#{e.class}> - #{e}"
|
67
|
+
STDERR.puts " ** try running as root?" if e.is_a? Dnet::HandleError
|
72
68
|
exit 1
|
73
69
|
ensure
|
74
70
|
blob.release
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: emonti-dnet-ffi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Monti
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-09-
|
12
|
+
date: 2009-09-17 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -59,6 +59,8 @@ files:
|
|
59
59
|
- lib/dnet/typedefs.rb
|
60
60
|
- lib/dnet/udp.rb
|
61
61
|
- lib/dnet/util.rb
|
62
|
+
- samples/eth_send_raw.rb
|
63
|
+
- samples/ifconfig-alike.rb
|
62
64
|
- samples/udp_send_raw.rb
|
63
65
|
- spec/addr_spec.rb
|
64
66
|
- spec/arp_spec.rb
|
@@ -76,6 +78,7 @@ files:
|
|
76
78
|
- spec/tun_spec.rb
|
77
79
|
has_rdoc: false
|
78
80
|
homepage: http://github.com/emonti/dnet-ffi
|
81
|
+
licenses:
|
79
82
|
post_install_message:
|
80
83
|
rdoc_options:
|
81
84
|
- --charset=UTF-8
|
@@ -96,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
99
|
requirements: []
|
97
100
|
|
98
101
|
rubyforge_project:
|
99
|
-
rubygems_version: 1.
|
102
|
+
rubygems_version: 1.3.5
|
100
103
|
signing_key:
|
101
104
|
specification_version: 3
|
102
105
|
summary: Ruby FFI bindings for libdnet
|