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