datalink-socket 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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