datalink-socket 0.0.1

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/README.rdoc ADDED
@@ -0,0 +1,58 @@
1
+ = A Datalink-Socket for OSX and Linux
2
+
3
+ To receive and send ethernet frames using ruby.
4
+
5
+ * Datalink::Socket class
6
+ * Ethernet::Socket class < Datalink::Socket
7
+ * Ethernet::Frame class
8
+ * Arp class
9
+
10
+ == Arp
11
+
12
+ > Arp.methods false
13
+ => [:new_request, :new_reply]
14
+
15
+ > Arp.new_request :hw_src=> '00:50:56:c0:00:01',
16
+ :proto_src=> '192.168.1.10',
17
+ :proto_tgt=> '192.168.1.13'
18
+ => ARP, Request who-has 192.168.1.13 tell 192.168.1.10
19
+
20
+ == Frame
21
+
22
+ > data, _ = s.recv
23
+ =>
24
+ > frame = Ethernet::Frame.new data
25
+ => #<Ethernet::Frame:0x00000100c94b08 ... >
26
+ > frame.src
27
+ => 00:24:b2:51:a8:8e
28
+ > frame.dst
29
+ => 00:1f:5b:ce:bd:6a
30
+ > frame.ether_type
31
+ => 2048
32
+ > frame.payload.unpack('H*')
33
+ => ["45200034d5ae400035061ad .... 08195fba"]
34
+
35
+
36
+ == Receiving
37
+
38
+ require 'ethernet'
39
+ s = Ethernet::Socket.new "en1"
40
+ s.open
41
+ s.recv
42
+
43
+
44
+ == Sending
45
+
46
+ request = Arp.new_request :hw_src=> '00:50:56:c0:00:01',
47
+ :proto_src=> '192.168.1.10',
48
+ :proto_tgt=> '192.168.1.13'
49
+
50
+ s.send request
51
+
52
+ = Installation
53
+
54
+ gem install datalink-socket
55
+
56
+ = License
57
+
58
+ Copyright (c) 2011 Jean-Michel Esnault. Released under the same license as Ruby
data/lib/arp.rb ADDED
@@ -0,0 +1,87 @@
1
+ require 'ethernet'
2
+ require 'ipaddr'
3
+
4
+ class Arp
5
+ include Args
6
+
7
+ HwSrc = Class.new(Ethernet::Address)
8
+ HwTgt = Class.new(Ethernet::Address)
9
+ ProtoSrc = Class.new(IPAddr)
10
+ ProtoTgt = Class.new(IPAddr)
11
+
12
+ attr_reader :hw_src, :hw_tgt, :proto_src, :proto_tgt, :opcode
13
+
14
+ def initialize(arg={})
15
+ if arg.is_a?(Hash)
16
+ @hw_tgt = HwTgt.new
17
+ @opcode, @hw_src, @proto_src, @proto_tgt = 1, nil, nil, nil
18
+ set arg
19
+ elsif arg.is_a?(String)
20
+ parse arg
21
+ else
22
+ end
23
+ end
24
+
25
+ def encode
26
+ s=[]
27
+ hw_src = @hw_src.encode
28
+ proto_src = @proto_src.hton
29
+ hw_tgt = @hw_tgt.encode
30
+ proto_tgt = @proto_tgt.hton
31
+ s << eth_hdr
32
+ s << [1,0x0800, 6, 4, @opcode, hw_src, proto_src, hw_tgt, proto_tgt].pack("nnCCn"+"a6a4"*2)
33
+ s.join
34
+ end
35
+
36
+ def parse(s)
37
+ # p s.unpack('H*')
38
+ # p s.size
39
+ s.slice!(0,14) if s.size>32
40
+ htype, ptype, hlen, plen, opcode = s.unpack('nnccn')
41
+ # p htype
42
+ # p ptype
43
+ hw_src, proto_src, hw_tgt, proto_tgt = s[8..-1].unpack("a#{hlen}a#{plen}"*2)
44
+ raise RuntimeError, "Unsupported Hardware Type" unless htype == 1 && ptype == 0x0800
45
+ @hw_src = HwSrc.new(hw_src)
46
+ @hw_tgt = HwTgt.new(hw_tgt)
47
+ @proto_src = ProtoSrc.ntop(proto_src)
48
+ @proto_tgt = ProtoTgt.ntop(proto_tgt)
49
+ @opcode = opcode
50
+ end
51
+
52
+ def to_s
53
+ case @opcode
54
+ when 1 ; "ARP, Request who-has #{@proto_tgt} tell #{@proto_src}"
55
+ when 2 ; "ARP, Reply #{@proto_src} is-at #{@hw_src}"
56
+ end
57
+ end
58
+
59
+ def reply(hw_src)
60
+ self.class.new_reply :hw_src=> hw_src, :proto_src=> "#{@proto_tgt}",
61
+ :hw_tgt => "#{@hw_src}", :proto_tgt => "#{@proto_src}"
62
+ end
63
+
64
+ class << self
65
+ def Arp.new_request(arg={})
66
+ if arg.is_a?(Hash)
67
+ arg[:opcode]=1
68
+ new arg
69
+ end
70
+ end
71
+ def Arp.new_reply(arg={})
72
+ if arg.is_a?(Hash)
73
+ arg[:opcode]=2
74
+ new arg
75
+ end
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def eth_hdr
82
+ src = @hw_src.to_s
83
+ dst = @opcode == 1 ? 'ffff.ffff.ffff' : @hw_tgt.to_s
84
+ f = ::Ethernet::Frame.new :dst=> dst, :src=> src
85
+ f.encode(::Ethernet::Type::ETH_ARP)
86
+ end
87
+ end
data/lib/dl_socket.rb ADDED
@@ -0,0 +1 @@
1
+ require "dl_socket_#{`uname`.chomp.downcase}"
@@ -0,0 +1,113 @@
1
+ module Datalink
2
+
3
+ BIOCGBLEN = 0x40044266
4
+ BIOCSBLEN = 0xc0044266
5
+ BIOCSETF = 0x80084267
6
+ BIOCFLUSH = 0x20004268
7
+ BIOCPROMISC = 0x20004269
8
+ BIOCGDLT = 0x4004426a
9
+ BIOCGETIF = 0x4020426b
10
+ BIOCSETIF = 0x8020426c
11
+ BIOCSRTIMEOUT = 0x8008426d
12
+ BIOCGRTIMEOUT = 0x4008426e
13
+ BIOCGSTATS = 0x4008426f
14
+ BIOCIMMEDIATE = 0x80044270
15
+ BIOCVERSION = 0x40044271
16
+ BIOCGRSIG = 0x40044272
17
+ BIOCSRSIG = 0x80044273
18
+ BIOCGHDRCMPLT = 0x40044274
19
+ BIOCSHDRCMPLT = 0x80044275
20
+ BIOCGSEESENT = 0x40044276
21
+ BIOCSSEESENT = 0x80044277
22
+ BIOCSDLT = 0x80044278
23
+ BIOCGDLTLIST = 0xc00c4279
24
+
25
+ class Socket
26
+
27
+ attr_accessor :if_name
28
+ attr_reader :device_name, :device
29
+
30
+ def initialize(if_name)
31
+ @if_name = if_name
32
+ end
33
+
34
+ def open(if_name=@if_name)
35
+ num=0
36
+ @if_name = if_name
37
+ begin
38
+ bpf_name = "/dev/bpf#{num}"
39
+ @file_handle = File.open(bpf_name, "w+")
40
+ rescue => error
41
+ if num < 30 and not defined?(@file_handle)
42
+ num +=1
43
+ retry
44
+ else
45
+ raise RuntimeError, "could not open #{bpf_name}: #{error}"
46
+ end
47
+ end
48
+
49
+ @file_handle_name = bpf_name
50
+ @file_handle.ioctl(BIOCSETIF, [@if_name].pack("a#{@if_name.size+1}"))
51
+ @file_handle.ioctl(BIOCIMMEDIATE, [1].pack('I'))
52
+ @file_handle.ioctl(BIOCGHDRCMPLT, [0].pack('N'))
53
+ buf = [0].pack('i')
54
+ @file_handle.ioctl(BIOCGBLEN, buf)
55
+ @buf_size = buf.unpack('i')[0]
56
+ timeout = [5,0].pack('LL')
57
+ @file_handle.ioctl(BIOCSRTIMEOUT, timeout)
58
+ self
59
+ end
60
+
61
+ def send(obj)
62
+ @file_handle.write_nonblock(obj.respond_to?(:encode) ? obj.encode : obj)
63
+ end
64
+
65
+ def recv
66
+ __recv
67
+ end
68
+
69
+ def close
70
+ @file_handle.close
71
+ end
72
+
73
+ private
74
+
75
+ def sysread_nb
76
+ buf=''
77
+ @file_handle.sysread(@buf_size, buf)
78
+ buf
79
+ end
80
+
81
+ def sysread
82
+ begin
83
+ buf = sysread_nb
84
+ return buf
85
+ rescue EOFError, Errno::EAGAIN => e
86
+ sleep(0.25)
87
+ retry
88
+ end
89
+ end
90
+
91
+ def __recv
92
+ @recvQueue ||=[]
93
+ @packet_size ||= lambda { |n| n+3 & ~3 }
94
+ @header_decode ||= lambda { |hdr|
95
+ datalen = hdr.slice(12,4).unpack('L')[0]
96
+ hdrlen = hdr.slice(16,2).unpack('v')[0]
97
+ size = @packet_size.call(datalen+hdrlen)
98
+ [size, hdrlen]
99
+ }
100
+ if @recvQueue.empty?
101
+ bpf_frames = sysread
102
+ while bpf_frames.size>0
103
+ size, hdrlen = @header_decode.call(bpf_frames)
104
+ @recvQueue << bpf_frames.slice!(0,size)[hdrlen..-1]
105
+ end
106
+ __recv
107
+ else
108
+ @recvQueue.shift
109
+ end
110
+ end
111
+ end
112
+ end
113
+
@@ -0,0 +1,83 @@
1
+ require 'socket'
2
+
3
+ module Datalink
4
+ class Socket < ::Socket
5
+
6
+ IFF_UP = 0x0001
7
+ IFF_BROADCAST = 0x0002
8
+ IFF_DEBUG = 0x0004
9
+ IFF_LOOPBACK = 0x0008
10
+ IFF_P2P = 0x0010
11
+ IFF_NOTRAILERS = 0x0020
12
+ IFF_RUNNING = 0x0040
13
+ IFF_NOARP = 0x0080
14
+ IFF_PROMISC = 0x0100
15
+ IFF_ALLMULTI = 0x0200
16
+ IFF_MASTER = 0x0400
17
+ IFF_SLAVE = 0x0800
18
+ IFF_MULTICAST = 0x1000
19
+ SIOCGIFINDEX = 0x8933
20
+ SIOCGIFFLAGS = 0x8913
21
+ SIOCSIFFLAGS = 0x8914
22
+ PF_PACKET = 17
23
+ AF_PACKET = PF_PACKET
24
+ IFNAMSIZ = 16
25
+
26
+ def flags
27
+ read_flags
28
+ end
29
+ self.class.constants.reject { |c| !( c =~/^IFF_/) }.collect { |f| f.to_s.split('_')[1].downcase}.each do |f|
30
+ define_method("#{f}?") do
31
+ flags & self.class.const_get("IFF_#{f.upcase}") > 0
32
+ end
33
+ define_method("set_#{f}") do
34
+ flags = read_flags
35
+ flags |= self.class.const_get("IFF_#{f.upcase}")
36
+ write_flags(flags)
37
+ end
38
+ define_method("unset_#{f}") do
39
+ flags = read_flags
40
+ flags &= ~self.class.const_get("IFF_#{f.upcase}")
41
+ write_flags(flags)
42
+ end
43
+ end
44
+
45
+ def initialize(if_name, proto=0x003)
46
+ @if_name = if_name
47
+ super(PF_PACKET, Socket::SOCK_RAW, proto)
48
+ ifreq = [if_name.dup].pack 'a32'
49
+ ioctl(SIOCGIFINDEX, ifreq)
50
+ bind [AF_PACKET].pack('s') + [proto].pack('n') + ifreq[16..20]+ ("\x00" * 12)
51
+ end
52
+
53
+ def recv
54
+ data, from = recvfrom(2048)
55
+ ether_type = data[12,2].unpack('n')[0]
56
+ [data, ether_type, Time.now]
57
+ end
58
+
59
+ def send(obj)
60
+ if obj.respond_to?(:encode)
61
+ super(obj.encode,0)
62
+ else
63
+ super(obj,0)
64
+ end
65
+ end
66
+
67
+ def open
68
+ end
69
+
70
+ private
71
+
72
+ def read_flags
73
+ ifreq = [@if_name.dup].pack "a#{IFNAMSIZ}"
74
+ ioctl(SIOCGIFFLAGS,ifreq)
75
+ ifreq[IFNAMSIZ,2].unpack('s')[0]
76
+ end
77
+
78
+ def write_flags(flags)
79
+ ifreq = [@if_name.dup].pack("a#{IFNAMSIZ}") + [flags].pack('s')
80
+ ioctl(SIOCSIFFLAGS,ifreq)
81
+ end
82
+ end
83
+ end
data/lib/ethernet.rb ADDED
@@ -0,0 +1,165 @@
1
+ require 'ruby-ext'
2
+ require 'dl_socket'
3
+ require 'rubygems'
4
+ # require 'oui'
5
+
6
+ module Ethernet
7
+ class Socket < Datalink::Socket
8
+ def recv(*args)
9
+ eth_frame = super
10
+ eth_type = eth_frame.slice(12,2).unpack('n')[0]
11
+ [eth_frame, eth_type]
12
+ end
13
+ end
14
+
15
+ module Type
16
+ ETH_IPv4 = 0x0800
17
+ ETH_ARP = 0x0806
18
+ ETH_RARP = 0x8035
19
+ ETH_Ethertalk = 0x809B
20
+ ETH_AARP = 0x80F3
21
+ ETH_IEEE_802_1Q = 0x8100
22
+ ETH_IPv6 = 0x86DD
23
+ def self.to_s(type)
24
+ case type
25
+ when ETH_IPv4 ; 'IPv4'
26
+ when ETH_IPv6 ; 'IPv6'
27
+ when ETH_ARP ; 'ARP'
28
+ when ETH_RARP ; 'RARP'
29
+ when ETH_Ethertalk ; 'AppleTalk Ethertalk'
30
+ when ETH_AARP ; 'AppleTalk Address Resolution Protocol'
31
+ when ETH_IEEE_802_1Q ; 'IEEE_802_1Q'
32
+ else
33
+ format("0x%04x",type)
34
+ end
35
+ end
36
+
37
+ end
38
+ class Address
39
+ attr_reader :mac
40
+
41
+ def initialize(arg=nil)
42
+ if arg.is_a?(String) and arg.size==6
43
+ parse(arg)
44
+ elsif arg.is_a?(String) and arg.size==14
45
+ parse [arg.split('.').join].pack('H*')
46
+ elsif arg.is_a?(String)
47
+ @mac = arg.split(/[-:]/).collect { |n| n.to_i(16) }
48
+ elsif arg.is_a?(String) and size==14
49
+ elsif arg.kind_of?(self.class)
50
+ parse arg.encode
51
+ elsif arg.kind_of?(self.class)
52
+ parse arg.encode
53
+ elsif ! arg
54
+ @mac = [0,0,0,0,0,0]
55
+ else
56
+ raise ArgumentError, "Argument error: #{self.class} #{arg.inspect}"
57
+ end
58
+ end
59
+
60
+ def to_s(delim=":")
61
+ case delim
62
+ when ':'
63
+ (format (["%02x"]*6).join(delim), *@mac)
64
+ when '.'
65
+ (format (["%04x"]*3).join(delim), *(@mac.pack('C6').unpack('n3')))
66
+ end
67
+ end
68
+
69
+ # def to_s_oui
70
+ # comp_id = Ethernet::OUI.company_id_from_arr(@mac[0..2])
71
+ # if comp_id == 'Unknown'
72
+ # to_s.downcase
73
+ # else
74
+ # s = []
75
+ # s << comp_id
76
+ # s << (format (["%02x"]*3).join(":"), *@mac[3..5])
77
+ # s.join('_')
78
+ # end
79
+ # end
80
+
81
+ def encode
82
+ @mac.pack('C*')
83
+ end
84
+
85
+ def to_hash
86
+ to_s
87
+ end
88
+
89
+ private
90
+
91
+ def parse(s)
92
+ @mac = s.unpack('C6')
93
+ end
94
+ end
95
+
96
+ include Type
97
+
98
+ def self.packet_factory(frame, ether_type, time)
99
+ s = frame.dup
100
+ case ether_type
101
+ when IPv4 ; puts "IPv4:"
102
+ when IPv6 ; puts "IPv6:"
103
+ when ARP ; puts "ARP:"
104
+ when RARP ; puts "RARP:"
105
+ else
106
+ puts "Ether_type: #{ether_type}:"
107
+ end
108
+ puts s.unpack('H*')
109
+ end
110
+
111
+ class Frame
112
+ include Args
113
+ Src = Class.new(Address)
114
+ Dst = Class.new(Address)
115
+ attr_reader :src, :dst, :ether_type, :payload
116
+ attr_writer_delegate :src, :dst
117
+ def initialize(arg={})
118
+ if arg.is_a?(Hash)
119
+ @src = Src.new
120
+ @dst = Dst.new
121
+ @ether_type=0
122
+ set(arg)
123
+ elsif arg.is_a?(String)
124
+ parse arg
125
+ else
126
+ raise ArgumentError, "Invalid argument :#{arg.inspect}"
127
+ end
128
+ end
129
+ def encode(ether_type=@ether_type, payload=nil)
130
+ @ether_type = ether_type if ether_type
131
+ @payload = payload if payload
132
+ frame = []
133
+ frame << @dst.encode
134
+ frame << @src.encode
135
+ frame << [ether_type].pack('n')
136
+ if @payload
137
+ if @payload.respond_to?(:encode)
138
+ frame << @payload.encode if @payload.respond_to?(:encode)
139
+ else
140
+ frame << @payload
141
+ end
142
+ end
143
+ frame.join
144
+ end
145
+ def parse(s)
146
+ self.dst = s.slice!(0,6)
147
+ self.src = s.slice!(0,6)
148
+ @ether_type = s.slice!(0,2).unpack('n')[0]
149
+ @payload = s
150
+ end
151
+ def ieee_802_3?
152
+ type? == :ieee_802_3
153
+ end
154
+ def ethernet_v2?
155
+ type? == :ethernet_v2
156
+ end
157
+ def type?
158
+ if @ether_type < 0x600
159
+ :ieee_802_3
160
+ else
161
+ :ethernet_v2
162
+ end
163
+ end
164
+ end
165
+ end
data/lib/ruby-ext.rb ADDED
@@ -0,0 +1,108 @@
1
+
2
+ class Object
3
+ def to_shex(*args)
4
+ self.respond_to?(:encode) ? self.encode(*args).unpack('H*')[0] : ""
5
+ end
6
+ alias to_s_hexlify to_shex
7
+ end
8
+
9
+ class Class
10
+ def attr_checked(attribute, &validation)
11
+ define_method "#{attribute}=" do |val|
12
+ raise "Invalid attribute #{val.inspect}" unless validation.call(val)
13
+ instance_variable_set("@#{attribute}", val)
14
+ end
15
+ define_method attribute do
16
+ instance_variable_get "@#{attribute}"
17
+ end
18
+ end
19
+ def attr_writer_delegate(*args)
20
+ args.each do |name|
21
+ define_method "#{name}=" do |value|
22
+ instance_variable_set("@#{name}", self.class.const_get(name.to_s.to_camel.to_sym).new(value))
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ class String
29
+ def to_underscore
30
+ gsub(/([A-Z]+|[A-Z][a-z])/) {|x| ' ' + x }.gsub(/[A-Z][a-z]+/) {|x| ' ' + x }.split.collect{|x| x.downcase}.join('_')
31
+ end
32
+ def to_camel
33
+ split('_').collect {|x| x.capitalize}.join
34
+ end
35
+ def hexlify
36
+ l,n,ls,s=0,0,[''],self.dup
37
+ while s.size>0
38
+ l = s.slice!(0,16)
39
+ ls << format("0x%4.4x: %s", n, l.unpack("n#{l.size/2}").collect { |x| format("%4.4x",x) }.join(' '))
40
+ n+=1
41
+ end
42
+ if l.size%2 >0
43
+ ns = l.size>1 ? 1 : 0
44
+ ls.last << format("%s%2.2x",' '*ns,l[-1].pack('C')[0])
45
+ end
46
+ ls
47
+ end
48
+ end
49
+
50
+ class Symbol
51
+ def to_klass
52
+ to_s.to_camel.to_sym
53
+ end
54
+ def to_setter
55
+ (to_s + "=").to_sym
56
+ end
57
+ end
58
+
59
+ module Args
60
+ def set(h)
61
+ for key in [ivars].flatten
62
+ if h.has_key?(key) and ! h[key].nil?
63
+ begin
64
+ klassname = key.to_klass
65
+ if self.class.const_defined?(klassname)
66
+ instance_variable_set("@#{key.to_s}", self.class.const_get(klassname).new(h[key]))
67
+ elsif self.respond_to?(key.to_setter)
68
+ self.send key.to_setter, h[key]
69
+ else
70
+ instance_variable_set("@#{key.to_s}", h[key])
71
+ end
72
+ rescue ArgumentError => e
73
+ raise
74
+ ensure
75
+ #h.delete(key)
76
+ end
77
+ else
78
+ end
79
+ end
80
+ end
81
+
82
+ def to_hash
83
+ h = {}
84
+ for key in [ivars].flatten
85
+ ivar = instance_variable_get("@#{key.to_s}")
86
+ if ivar.respond_to?(:to_hash)
87
+ h.store(key,ivar.to_hash)
88
+ elsif ivar.is_a?(Array)
89
+ h.store(key, ivar.collect { |x|
90
+ if x.respond_to?(:to_hash)
91
+ x.to_hash
92
+ else
93
+ # x.to_s
94
+ nil
95
+ end
96
+ }
97
+ )
98
+ else
99
+ h.store(key,ivar) unless ivar.nil?
100
+ end
101
+ end
102
+ h
103
+ end
104
+
105
+ def ivars
106
+ instance_variables.reject { |x| x =~ /^@_/ }.collect { |x| x[1..-1].to_sym }
107
+ end
108
+ end
data/test/arp_test.rb ADDED
@@ -0,0 +1,18 @@
1
+ require "test/unit"
2
+ require "arp"
3
+ class TestNetArp2 < Test::Unit::TestCase
4
+ def test_arp_request
5
+ req = Arp.new_request :hw_src=> '1:2:3:4:5:6', :proto_src=> '10.0.0.1', :proto_tgt=>'10.0.0.2'
6
+ assert_equal(1, req.opcode)
7
+ assert_equal('01:02:03:04:05:06', req.hw_src.to_s)
8
+ assert_equal('00:00:00:00:00:00', req.hw_tgt.to_s)
9
+ assert_equal('10.0.0.1', req.proto_src.to_s)
10
+ assert_equal('10.0.0.2', req.proto_tgt.to_s)
11
+ assert_equal('ffffffffffff010203040506080600010800060400010102030405060a0000010000000000000a000002', req.to_shex)
12
+ end
13
+ def test_arp_reply
14
+ req = Arp.new_request :hw_src=> '1:2:3:4:5:6', :proto_src=> '10.0.0.1', :proto_tgt=>'10.0.0.2'
15
+ reply = req.reply '00:50:56:c0:00:01'
16
+ #TODO finish test
17
+ end
18
+ end
@@ -0,0 +1,71 @@
1
+ require "test/unit"
2
+
3
+ require "ethernet"
4
+
5
+ class TestEthernetIeAddress < Test::Unit::TestCase
6
+ def test_create_address
7
+ assert Ethernet::Address.new
8
+ assert Ethernet::Address.new '00:01:02:03:04:05'
9
+ assert_equal '01:02:03:04:05:06', Ethernet::Address.new('1:2:3:4:5:6').to_s
10
+ assert_equal '0a:0b:0c:0d:0e:0f', Ethernet::Address.new('a:b:c:d:e:f').to_s
11
+ assert_equal '00:b0:64:fd:4f:6c', Ethernet::Address.new('00b0.64fd.4f6c').to_s
12
+ end
13
+ def test_to_s
14
+ assert_equal '0102.0304.0506', Ethernet::Address.new('1:2:3:4:5:6').to_s('.')
15
+ assert_equal '0a0b.0c0d.0e0f', Ethernet::Address.new('a:b:c:d:e:f').to_s('.')
16
+ assert_equal '00b0.64fd.4f6c', Ethernet::Address.new('00b0.64fd.4f6c').to_s('.')
17
+ end
18
+ def test_encode
19
+ assert_equal '010203040506', Ethernet::Address.new('1:2:3:4:5:6').to_shex
20
+ assert_equal '0a0b0c0d0e0f', Ethernet::Address.new('a:b:c:d:e:f').to_shex
21
+ end
22
+ def test_parse
23
+ assert_equal Ethernet::Address, Ethernet::Address.new(['010203040506'].pack('H*')).class
24
+ assert_equal '010203040506', Ethernet::Address.new(['010203040506'].pack('H*')).to_shex
25
+ end
26
+ # def test_to_s_oui
27
+ # assert_equal 'Apple_d8:93:a4', Ethernet::Address.new('00:1f:f3:d8:93:a4').to_s_oui
28
+ # assert_equal 'Dell_01:3e:3d', Ethernet::Address.new('00:21:9b:01:3e:3d').to_s_oui
29
+ # assert_equal 'Hewlett_64:66:73', Ethernet::Address.new('00:50:8b:64:66:73').to_s_oui
30
+ # assert_equal 'Intel_40:b8:8f', Ethernet::Address.new('0:2:b3:40:b8:8f').to_s_oui
31
+ # assert_equal 'Cisco_fd:4f:6c', Ethernet::Address.new('00b0.64fd.4f6c').to_s_oui
32
+ # end
33
+ end
34
+
35
+ class TestEthernetType < Test::Unit::TestCase
36
+ def test_case_name
37
+ assert_equal 2054, Ethernet::Type::ETH_ARP
38
+ assert_equal 2048, Ethernet::Type::ETH_IPv4
39
+ assert_equal 34525, Ethernet::Type::ETH_IPv6
40
+ assert_equal 32821, Ethernet::Type::ETH_RARP
41
+ assert_equal 'ARP',Ethernet::Type.to_s(2054)
42
+ assert_equal 'RARP',Ethernet::Type.to_s(32821)
43
+ assert_equal 'IPv4',Ethernet::Type.to_s(2048)
44
+ assert_equal 'AppleTalk Ethertalk',Ethernet::Type.to_s(0x809B)
45
+ end
46
+ end
47
+
48
+ class TestEthernetFrame < Test::Unit::TestCase
49
+ include Ethernet
50
+ def test_create_a_frame
51
+ frame = Ethernet::Frame.new :src=> '0001.0002.0003', :dst=>'0004.0005.0006', :ether_type=>0x800
52
+ assert_equal '00:01:00:02:00:03', frame.src.to_s
53
+ assert_equal '00:04:00:05:00:06', frame.dst.to_s
54
+ assert_equal 2048, frame.ether_type
55
+ frame = Ethernet::Frame.new(['0004000500060001000200030800'].pack('H*'))
56
+ assert_equal '00:01:00:02:00:03', frame.src.to_s
57
+ assert_equal '00:04:00:05:00:06', frame.dst.to_s
58
+ assert_equal 2048, frame.ether_type
59
+ end
60
+ def test_create_ntop_ip
61
+ s = '01005e00000500b064fd4f6c0800' +
62
+ '45c0004084fe000001599131c0a801c8e0000005' +
63
+ '0201002c0200000000000000fa1f00000000000000000000ffffff00000a0280000000280000000000000000'
64
+ sbin = [s].pack('H*')
65
+ frame = Frame.new(sbin)
66
+ # assert_equal 'Cisco_fd:4f:6c', frame.src.to_s_oui
67
+ # assert_equal '01:00:5e:00:00:05', frame.dst.to_s_oui
68
+ assert_equal 2048, frame.ether_type
69
+ assert_equal '45c0004084fe000001599131c0a801c8e000000502', frame.payload[0..20].unpack('H*')[0]
70
+ end
71
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: datalink-socket
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Jean-Michel Esnault
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-05 00:00:00 -08:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Datalink Socket
22
+ email: jesnault@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - README.rdoc
31
+ - lib/arp.rb
32
+ - lib/dl_socket.rb
33
+ - lib/dl_socket_darwin.rb
34
+ - lib/dl_socket_linux.rb
35
+ - lib/ethernet.rb
36
+ - lib/ruby-ext.rb
37
+ - test/arp_test.rb
38
+ - test/ethernet_test.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/jesnault/dl
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --quiet
46
+ - --title
47
+ - Datalink Socket
48
+ - --line-numbers
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 1
58
+ - 8
59
+ - 6
60
+ version: 1.8.6
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.3.7
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Datalink Socket
76
+ test_files:
77
+ - test/arp_test.rb
78
+ - test/ethernet_test.rb