emonti-dnet-ffi 0.1.2 → 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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
@@ -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.2"
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-13}
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",
@@ -23,7 +23,8 @@ module Dnet
23
23
  class Addr < ::FFI::Struct
24
24
  include ::FFI::DRY::StructHelper
25
25
 
26
- ADDR_TYPES = [ nil, :eth, :ip, :ip6 ] # A mapping of dnet address types
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.
@@ -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
- raise "bad mac address" unless s =~ MAC_RX
20
- raw = ::Dnet::Util.unhexify(s, /[:-]/)
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.
@@ -53,7 +53,7 @@ module Dnet
53
53
  def self.list; @@list ||= super(); end
54
54
  end
55
55
 
56
- def lookup_itype; Flags[self[:itype]]; end
56
+ def lookup_itype; Itype[self[:itype]]; end
57
57
 
58
58
  # Returns a newly instantiated and allocated copy of this interface entry
59
59
  def copy
@@ -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
@@ -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
+
@@ -54,21 +54,17 @@ blob.write(udp_hdr.to_ptr, Udp::Hdr.size)
54
54
  blob.write(data)
55
55
 
56
56
  begin
57
- 10.times do
58
- blob.rewind
59
- sent = Ip::Handle.open { |h| h.ip_send(blob.read) }
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
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.2
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-13 00:00:00 -07:00
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.2.0
102
+ rubygems_version: 1.3.5
100
103
  signing_key:
101
104
  specification_version: 3
102
105
  summary: Ruby FFI bindings for libdnet