ethernet 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.project +11 -0
- data/Gemfile +10 -6
- data/Gemfile.lock +15 -11
- data/README.rdoc +1 -1
- data/Rakefile +7 -10
- data/VERSION +1 -1
- data/bin/ethernet_ping +30 -0
- data/ethernet.gemspec +36 -21
- data/lib/ethernet/devices.rb +41 -0
- data/lib/ethernet/frame_socket.rb +122 -0
- data/lib/ethernet/ping.rb +89 -0
- data/lib/ethernet/provisioning.rb +44 -0
- data/lib/ethernet/raw_socket_factory.rb +91 -0
- data/lib/ethernet.rb +48 -0
- data/spec/ethernet/devices_spec.rb +39 -0
- data/spec/ethernet/frame_socket_spec.rb +102 -0
- data/spec/ethernet/raw_socket_factory_spec.rb +26 -0
- data/spec/ethernet_spec.rb +41 -3
- data/spec/support/ifconfig_cli.rb +37 -0
- data/spec/support/raw_socket_stub.rb +23 -0
- metadata +95 -27
data/.project
ADDED
data/Gemfile
CHANGED
@@ -1,13 +1,17 @@
|
|
1
|
-
source
|
1
|
+
source 'http://rubygems.org'
|
2
2
|
# Add dependencies required to use your gem here.
|
3
3
|
# Example:
|
4
|
-
# gem
|
4
|
+
# gem 'activesupport', '>= 2.3.5'
|
5
|
+
|
6
|
+
gem 'system-getifaddrs', '~> 0.1.1', :platform => :ruby,
|
7
|
+
:require => 'system/getifaddrs'
|
5
8
|
|
6
9
|
# Add dependencies to develop your gem here.
|
7
10
|
# Include everything needed to run rake, tests, features, etc.
|
8
11
|
group :development do
|
9
|
-
gem
|
10
|
-
gem
|
11
|
-
gem
|
12
|
-
gem
|
12
|
+
gem 'rdoc', '~> 3.6.1'
|
13
|
+
gem 'rspec', '~> 2.6.0'
|
14
|
+
gem 'bundler', '~> 1.0.0'
|
15
|
+
gem 'jeweler', '~> 1.6.0'
|
16
|
+
gem 'rcov', '>= 0'
|
13
17
|
end
|
data/Gemfile.lock
CHANGED
@@ -3,26 +3,30 @@ GEM
|
|
3
3
|
specs:
|
4
4
|
diff-lcs (1.1.2)
|
5
5
|
git (1.2.5)
|
6
|
-
jeweler (1.
|
6
|
+
jeweler (1.6.0)
|
7
7
|
bundler (~> 1.0.0)
|
8
8
|
git (>= 1.2.5)
|
9
9
|
rake
|
10
|
-
rake (0.
|
10
|
+
rake (0.9.0)
|
11
11
|
rcov (0.9.9)
|
12
|
-
|
13
|
-
|
14
|
-
rspec-
|
15
|
-
rspec-
|
16
|
-
|
17
|
-
rspec-
|
12
|
+
rdoc (3.6.1)
|
13
|
+
rspec (2.6.0)
|
14
|
+
rspec-core (~> 2.6.0)
|
15
|
+
rspec-expectations (~> 2.6.0)
|
16
|
+
rspec-mocks (~> 2.6.0)
|
17
|
+
rspec-core (2.6.3)
|
18
|
+
rspec-expectations (2.6.0)
|
18
19
|
diff-lcs (~> 1.1.2)
|
19
|
-
rspec-mocks (2.
|
20
|
+
rspec-mocks (2.6.0)
|
21
|
+
system-getifaddrs (0.1.1)
|
20
22
|
|
21
23
|
PLATFORMS
|
22
24
|
ruby
|
23
25
|
|
24
26
|
DEPENDENCIES
|
25
27
|
bundler (~> 1.0.0)
|
26
|
-
jeweler (~> 1.
|
28
|
+
jeweler (~> 1.6.0)
|
27
29
|
rcov
|
28
|
-
|
30
|
+
rdoc (~> 3.6.1)
|
31
|
+
rspec (~> 2.6.0)
|
32
|
+
system-getifaddrs (~> 0.1.1)
|
data/README.rdoc
CHANGED
@@ -16,10 +16,10 @@ This project is a low-level ethernet communication rubygems library. Its initial
|
|
16
16
|
|
17
17
|
== Author
|
18
18
|
|
19
|
+
Victor Costan victor@costan.us
|
19
20
|
HaoQi Li haoqili@mit.edu
|
20
21
|
|
21
22
|
== Copyright
|
22
23
|
|
23
24
|
Copyright (c) 2011 Massachusetts Institute of Technology.
|
24
25
|
See LICENSE.txt for further details.
|
25
|
-
|
data/Rakefile
CHANGED
@@ -13,16 +13,13 @@ require 'jeweler'
|
|
13
13
|
Jeweler::Tasks.new do |gem|
|
14
14
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
15
|
gem.name = "ethernet"
|
16
|
-
gem.homepage = "http://github.com/
|
16
|
+
gem.homepage = "http://github.com/costan/ethernet"
|
17
17
|
gem.license = "MIT"
|
18
|
-
gem.summary = %Q{
|
19
|
-
gem.description = %Q{
|
20
|
-
gem.email = "
|
21
|
-
gem.authors = ["HaoQi Li"]
|
22
|
-
#
|
23
|
-
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
24
|
-
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
25
|
-
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
18
|
+
gem.summary = %Q{Ethernet (link-layer level) sockets.}
|
19
|
+
gem.description = %Q{Provides a Socket-like API that bypasses TCP/IP. Useful for exotic devices and FPGA development.}
|
20
|
+
gem.email = "victor@costan.us"
|
21
|
+
gem.authors = ["Victor Costan", "HaoQi Li"]
|
22
|
+
# dependencies defined in Gemfile
|
26
23
|
end
|
27
24
|
Jeweler::RubygemsDotOrgTasks.new
|
28
25
|
|
@@ -39,7 +36,7 @@ end
|
|
39
36
|
|
40
37
|
task :default => :spec
|
41
38
|
|
42
|
-
require '
|
39
|
+
require 'rdoc/task'
|
43
40
|
Rake::RDocTask.new do |rdoc|
|
44
41
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
45
42
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.0
|
data/bin/ethernet_ping
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'ethernet' #'scratchpad'
|
4
|
+
|
5
|
+
if ARGV.length < 4
|
6
|
+
print <<END_USAGE
|
7
|
+
Usage: #{$0} net_interface ether_type dest_mac data
|
8
|
+
net_interface: name of the Ethernet interface, e.g. eth0
|
9
|
+
ether_type: packet type for the Ethernet II frame, in hex (2 bytes)
|
10
|
+
dest_mac: destination MAC for the ping packets, in hex (6 bytes)
|
11
|
+
data: ping packet data, in hex (0-padded to 64 bytes)
|
12
|
+
END_USAGE
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
|
16
|
+
interface = ARGV[0]
|
17
|
+
ether_type = [ARGV[1]].pack('H*').unpack('n').first
|
18
|
+
dest_mac = ARGV[2]
|
19
|
+
data = [ARGV[3]].pack('H*')
|
20
|
+
|
21
|
+
#client = Scratchpad::Ethernet::PingClient.new interface, ether_type, dest_mac
|
22
|
+
client = Ethernet::PingClient.new interface, ether_type, dest_mac
|
23
|
+
|
24
|
+
loop do
|
25
|
+
print "Pinging #{dest_mac}... "
|
26
|
+
STDOUT.flush
|
27
|
+
puts client.ping(data) ? "OK" : "Failed"
|
28
|
+
STDOUT.flush
|
29
|
+
sleep 1
|
30
|
+
end
|
data/ethernet.gemspec
CHANGED
@@ -5,19 +5,21 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ethernet}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = [
|
12
|
-
s.date = %q{2011-
|
13
|
-
s.description = %q{
|
14
|
-
s.email = %q{
|
11
|
+
s.authors = [%q{Victor Costan}, %q{HaoQi Li}]
|
12
|
+
s.date = %q{2011-05-27}
|
13
|
+
s.description = %q{Provides a Socket-like API that bypasses TCP/IP. Useful for exotic devices and FPGA development.}
|
14
|
+
s.email = %q{victor@costan.us}
|
15
|
+
s.executables = [%q{ethernet_ping}]
|
15
16
|
s.extra_rdoc_files = [
|
16
17
|
"LICENSE.txt",
|
17
18
|
"README.rdoc"
|
18
19
|
]
|
19
20
|
s.files = [
|
20
21
|
".document",
|
22
|
+
".project",
|
21
23
|
".rspec",
|
22
24
|
"Gemfile",
|
23
25
|
"Gemfile.lock",
|
@@ -25,39 +27,52 @@ Gem::Specification.new do |s|
|
|
25
27
|
"README.rdoc",
|
26
28
|
"Rakefile",
|
27
29
|
"VERSION",
|
30
|
+
"bin/ethernet_ping",
|
28
31
|
"ethernet.gemspec",
|
29
32
|
"lib/ethernet.rb",
|
33
|
+
"lib/ethernet/devices.rb",
|
34
|
+
"lib/ethernet/frame_socket.rb",
|
35
|
+
"lib/ethernet/ping.rb",
|
36
|
+
"lib/ethernet/provisioning.rb",
|
37
|
+
"lib/ethernet/raw_socket_factory.rb",
|
38
|
+
"spec/ethernet/devices_spec.rb",
|
39
|
+
"spec/ethernet/frame_socket_spec.rb",
|
40
|
+
"spec/ethernet/raw_socket_factory_spec.rb",
|
30
41
|
"spec/ethernet_spec.rb",
|
31
|
-
"spec/spec_helper.rb"
|
32
|
-
|
33
|
-
|
34
|
-
s.licenses = ["MIT"]
|
35
|
-
s.require_paths = ["lib"]
|
36
|
-
s.rubygems_version = %q{1.6.2}
|
37
|
-
s.summary = %q{A ruby gem library for ethernet communication.}
|
38
|
-
s.test_files = [
|
39
|
-
"spec/ethernet_spec.rb",
|
40
|
-
"spec/spec_helper.rb"
|
42
|
+
"spec/spec_helper.rb",
|
43
|
+
"spec/support/ifconfig_cli.rb",
|
44
|
+
"spec/support/raw_socket_stub.rb"
|
41
45
|
]
|
46
|
+
s.homepage = %q{http://github.com/costan/ethernet}
|
47
|
+
s.licenses = [%q{MIT}]
|
48
|
+
s.require_paths = [%q{lib}]
|
49
|
+
s.rubygems_version = %q{1.8.4}
|
50
|
+
s.summary = %q{Ethernet (link-layer level) sockets.}
|
42
51
|
|
43
52
|
if s.respond_to? :specification_version then
|
44
53
|
s.specification_version = 3
|
45
54
|
|
46
55
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
|
-
s.
|
56
|
+
s.add_runtime_dependency(%q<system-getifaddrs>, ["~> 0.1.1"])
|
57
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.6.1"])
|
58
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
|
48
59
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
49
|
-
s.add_development_dependency(%q<jeweler>, ["~> 1.
|
60
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
|
50
61
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
51
62
|
else
|
52
|
-
s.add_dependency(%q<
|
63
|
+
s.add_dependency(%q<system-getifaddrs>, ["~> 0.1.1"])
|
64
|
+
s.add_dependency(%q<rdoc>, ["~> 3.6.1"])
|
65
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
53
66
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
54
|
-
s.add_dependency(%q<jeweler>, ["~> 1.
|
67
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
55
68
|
s.add_dependency(%q<rcov>, [">= 0"])
|
56
69
|
end
|
57
70
|
else
|
58
|
-
s.add_dependency(%q<
|
71
|
+
s.add_dependency(%q<system-getifaddrs>, ["~> 0.1.1"])
|
72
|
+
s.add_dependency(%q<rdoc>, ["~> 3.6.1"])
|
73
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
59
74
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
60
|
-
s.add_dependency(%q<jeweler>, ["~> 1.
|
75
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
61
76
|
s.add_dependency(%q<rcov>, [">= 0"])
|
62
77
|
end
|
63
78
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# OS-dependent gem includes.
|
2
|
+
case RUBY_PLATFORM
|
3
|
+
when /linux/
|
4
|
+
when /darwin/
|
5
|
+
require 'system/getifaddrs'
|
6
|
+
end
|
7
|
+
|
8
|
+
# :nodoc: namespace
|
9
|
+
module Ethernet
|
10
|
+
|
11
|
+
# Information about the available Ethernet devices.
|
12
|
+
module Devices
|
13
|
+
# An array of device names for the machine's Ethernet devices.
|
14
|
+
def self.all
|
15
|
+
case RUBY_PLATFORM
|
16
|
+
when /linux/, /darwin/
|
17
|
+
System.get_ifaddrs.keys.map(&:to_s)
|
18
|
+
else
|
19
|
+
raise "Unsupported platform #{RUBY_PLATFORM}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# The MAC address for an Ethernet device.
|
24
|
+
#
|
25
|
+
# Args:
|
26
|
+
# eth_device:: device name for the Ethernet card, e.g. 'eth0'
|
27
|
+
def self.mac(eth_device)
|
28
|
+
case RUBY_PLATFORM
|
29
|
+
when /linux/
|
30
|
+
# /usr/include/net/if.h, structure ifreq
|
31
|
+
ifreq = [eth_device].pack 'a32'
|
32
|
+
# 0x8927 is SIOCGIFHWADDR in /usr/include/bits/ioctls.h
|
33
|
+
RawSocketFactory.socket.ioctl 0x8927, ifreq
|
34
|
+
ifreq[18, 6]
|
35
|
+
else
|
36
|
+
raise "Unsupported platform #{RUBY_PLATFORM}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end # class Ethernet::Devices
|
40
|
+
|
41
|
+
end # namespace Ethernet
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
module Ethernet
|
3
|
+
|
4
|
+
# Wraps an Ethernet socket and abstracts away the Ethernet II frame.
|
5
|
+
class FrameSocket
|
6
|
+
# Creates a wrapper around a raw Ethernet socket.
|
7
|
+
#
|
8
|
+
# Args:
|
9
|
+
# raw_socket_or_device:: a raw Ethernet socket or a string containing an
|
10
|
+
# Ethernet device name
|
11
|
+
# ether_type:: 2-byte Ethernet packet type number
|
12
|
+
# mac_address:: 6-byte MAC address for the Ethernet socket (optional if
|
13
|
+
# raw_socket_or_device is an Ethernet device name)
|
14
|
+
#
|
15
|
+
# Raises:
|
16
|
+
# RuntimeError:: if mac isn't exactly 6-bytes long
|
17
|
+
def initialize(raw_socket_or_device, ether_type, mac_address = nil)
|
18
|
+
check_mac mac_address if mac_address
|
19
|
+
|
20
|
+
if raw_socket_or_device.respond_to? :to_str
|
21
|
+
@source_mac = mac_address || Ethernet::Devices.mac(raw_socket_or_device)
|
22
|
+
@socket = RawSocketFactory.socket raw_socket_or_device, ether_type
|
23
|
+
else
|
24
|
+
raise 'MAC address needed with raw socket' unless mac_address
|
25
|
+
@source_mac = mac_address.dup
|
26
|
+
@socket = raw_socket_or_device
|
27
|
+
end
|
28
|
+
|
29
|
+
@dest_mac = nil
|
30
|
+
@ether_type = [ether_type].pack('n')
|
31
|
+
end
|
32
|
+
|
33
|
+
# Sets the destination MAC address for future calls to send.
|
34
|
+
#
|
35
|
+
# Args:
|
36
|
+
# mac:: 6-byte MAC address for the Ethernet socket
|
37
|
+
#
|
38
|
+
# Raises:
|
39
|
+
# RuntimeError:: if mac isn't exactly 6-bytes long
|
40
|
+
def connect(mac_address)
|
41
|
+
check_mac mac_address
|
42
|
+
@dest_mac = mac_address
|
43
|
+
end
|
44
|
+
|
45
|
+
# Closes the underlying socket.
|
46
|
+
def close
|
47
|
+
@socket.close
|
48
|
+
end
|
49
|
+
|
50
|
+
# Sends an Ethernet II frame.
|
51
|
+
#
|
52
|
+
# Args:
|
53
|
+
# data:: the data bytes to be sent
|
54
|
+
#
|
55
|
+
# Raises:
|
56
|
+
# RuntimeError:: if connect wasn' previously called
|
57
|
+
def send(data, send_flags = 0)
|
58
|
+
raise "Not connected" unless @dest_mac
|
59
|
+
send_to @dest_mac, data, send_flags
|
60
|
+
end
|
61
|
+
|
62
|
+
# Sends an Ethernet II frame.
|
63
|
+
#
|
64
|
+
# Args:
|
65
|
+
# mac_address:: the destination MAC address
|
66
|
+
# data:: the data bytes to be sent
|
67
|
+
#
|
68
|
+
# Raises:
|
69
|
+
# RuntimeError:: if connect wasn' previously called
|
70
|
+
def send_to(mac_address, data, send_flags = 0)
|
71
|
+
check_mac mac_address
|
72
|
+
|
73
|
+
padding = (data.length < 46) ? "\0" * (46 - data.length) : ''
|
74
|
+
packet = [mac_address, @source_mac, @ether_type, data, padding].join
|
75
|
+
@socket.send packet, send_flags
|
76
|
+
end
|
77
|
+
|
78
|
+
# Receives an Ethernet II frame.
|
79
|
+
#
|
80
|
+
# Args:
|
81
|
+
# buffer_size:: optional maximum packet size argument passed to the raw
|
82
|
+
# socket's recv method
|
83
|
+
#
|
84
|
+
# Returns the data and the source MAC address in the frame.
|
85
|
+
#
|
86
|
+
# This will discard incoming frames that don't match the MAC address that the
|
87
|
+
# socket is connected to, or the Ethernet packet type.
|
88
|
+
def recv(buffer_size = 8192)
|
89
|
+
raise "Not connected" unless @dest_mac
|
90
|
+
loop do
|
91
|
+
data, mac_address = recv_from buffer_size
|
92
|
+
return data if @dest_mac == mac_address
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Receives an Ethernet II frame.
|
97
|
+
#
|
98
|
+
# Args:
|
99
|
+
# buffer_size:: optional maximum packet size argument passed to the raw
|
100
|
+
# socket's recv method
|
101
|
+
#
|
102
|
+
# Returns the data in the frame.
|
103
|
+
#
|
104
|
+
# This will discard incoming frames that don't match the MAC address that the
|
105
|
+
# socket is connected to, or the Ethernet packet type.
|
106
|
+
def recv_from(buffer_size = 8192)
|
107
|
+
loop do
|
108
|
+
packet = @socket.recv buffer_size
|
109
|
+
next unless packet[12, 2] == @ether_type
|
110
|
+
next unless packet[0, 6] == @source_mac
|
111
|
+
return packet[14..-1], packet[6, 6]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Raises an exception if the given MAC address is invalid.
|
116
|
+
def check_mac(mac_address)
|
117
|
+
raise "Invalid MAC address" unless mac_address.length == 6
|
118
|
+
end
|
119
|
+
private :check_mac
|
120
|
+
end # class Ethernet::FrameSocket
|
121
|
+
|
122
|
+
end # namespace Ethernet
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# TODO(pwnall): move to separate gem
|
2
|
+
|
3
|
+
|
4
|
+
# copied from victor's scratchpad/lib/scratchpad/ethernet/ping.rb
|
5
|
+
# changes see raw_socket.rb
|
6
|
+
# :%s/if_name/eth_device/g
|
7
|
+
# .get_interface_mac() --> .mac()
|
8
|
+
# Ethernet.socket --> Ethernet::RawSocket.socket
|
9
|
+
# Ethernet.mac --> Ethernet::RawSocket.mac
|
10
|
+
|
11
|
+
# :nodoc: namespace # module Scratchpad
|
12
|
+
|
13
|
+
# :nodoc: namespace
|
14
|
+
module Ethernet
|
15
|
+
|
16
|
+
# Responder for ping utility using raw Ethernet sockets.
|
17
|
+
class PingServer
|
18
|
+
module Connection
|
19
|
+
def receive_data(packet)
|
20
|
+
source_mac = packet[0, 6].unpack('H*')
|
21
|
+
dest_mac = packet[6, 6].unpack('H*')
|
22
|
+
ether_type = packet[12, 2].unpack('H*')
|
23
|
+
|
24
|
+
puts "Src: #{source_mac} Dst: #{dest_mac} Eth: #{ether_type}\n"
|
25
|
+
puts packet[14..-1].unpack('H*')
|
26
|
+
|
27
|
+
# Exchange the source and destination ARP addresses.
|
28
|
+
packet[0, 6], packet[6, 6] = packet[6, 6], packet[0, 6]
|
29
|
+
send_data packet
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class ConnectionWrapper
|
34
|
+
include Connection
|
35
|
+
|
36
|
+
def initialize(socket)
|
37
|
+
@socket = socket
|
38
|
+
end
|
39
|
+
|
40
|
+
def send_data(data)
|
41
|
+
@socket.send data, 0
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def run
|
46
|
+
connection = ConnectionWrapper.new @socket
|
47
|
+
loop do
|
48
|
+
packet = @socket.recv 65536
|
49
|
+
connection.receive_data packet
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize(eth_device, ether_type)
|
54
|
+
@socket = Ethernet::RawSocket.socket eth_device, ether_type
|
55
|
+
end
|
56
|
+
end # module Ethernet::PingServer
|
57
|
+
|
58
|
+
# Ping utility
|
59
|
+
class PingClient
|
60
|
+
def initialize(eth_device, ether_type, destination_mac)
|
61
|
+
@socket = Ethernet::RawSocket.socket eth_device, ether_type
|
62
|
+
@source_mac = [Ethernet::RawSocket.mac(eth_device).unpack('H*').first].pack('H*')[0, 6]
|
63
|
+
@dest_mac = [destination_mac].pack('H*')[0, 6]
|
64
|
+
@ether_type = [ether_type].pack('n')
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_reader :socket
|
68
|
+
attr_reader :source_mac
|
69
|
+
attr_reader :dest_mac
|
70
|
+
|
71
|
+
# Pings over raw Ethernet sockets.
|
72
|
+
#
|
73
|
+
# Returns true if the ping receives a response, false otherwise.
|
74
|
+
def ping(data, timeout = 1)
|
75
|
+
data = data.clone
|
76
|
+
# Pad data to have at least 64 bytes.
|
77
|
+
data += "\0" * (64 - data.length) if data.length < 64
|
78
|
+
|
79
|
+
ping_packet = @dest_mac + @source_mac + @ether_type + data
|
80
|
+
@socket.send ping_packet, 0
|
81
|
+
|
82
|
+
response_packet = @source_mac + @dest_mac + @ether_type + data
|
83
|
+
response = @socket.recv response_packet.length * 2
|
84
|
+
|
85
|
+
response == response_packet
|
86
|
+
end
|
87
|
+
end # module Ethernet::PingClient
|
88
|
+
|
89
|
+
end # namespace Ethernet
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Ethernet
|
6
|
+
|
7
|
+
# Setup issues such as assigning permissions for Ethernet-level transmission.
|
8
|
+
module Provisioning
|
9
|
+
# Allow non-root users to create low-level Ethernet sockets.
|
10
|
+
#
|
11
|
+
# This is a security risk, because Ethernet sockets can be used to spy on all
|
12
|
+
# traffic on the machine's network. This should not be called on production
|
13
|
+
# machines.
|
14
|
+
#
|
15
|
+
# Returns true for success, false otherwise. If the call fails, it is most
|
16
|
+
# likely because it is not run by root / Administrator.
|
17
|
+
def self.usermode_sockets
|
18
|
+
case RUBY_PLATFORM
|
19
|
+
when /darwin/
|
20
|
+
return false unless Kernel.system("chmod o+r /dev/bpf*")
|
21
|
+
when /linux/
|
22
|
+
ruby = File.join Config::CONFIG['bindir'],
|
23
|
+
Config::CONFIG['ruby_install_name']
|
24
|
+
unless Kernel.system("setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' #{ruby}")
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
|
28
|
+
# Try to enable Wireshark packet capture for debugging.
|
29
|
+
# No big deal if this fails.
|
30
|
+
dumpcap = '/usr/bin/dumpcap'
|
31
|
+
if File.exist? dumpcap
|
32
|
+
Kernel.system("setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' #{dumpcap}")
|
33
|
+
end
|
34
|
+
when /win/
|
35
|
+
# NOTE: this might not work
|
36
|
+
return false unless Kernel.system("sc config npf start= auto")
|
37
|
+
else
|
38
|
+
raise "Unsupported platform #{RUBY_PLATFORM}"
|
39
|
+
end
|
40
|
+
true
|
41
|
+
end
|
42
|
+
end # class Ethernet::Provisioning
|
43
|
+
|
44
|
+
end # namespace Ethernet
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
case RUBY_PLATFORM
|
4
|
+
when /linux/
|
5
|
+
require 'system/getifaddrs' # for listing
|
6
|
+
end
|
7
|
+
|
8
|
+
# :nodoc: namespace
|
9
|
+
module Ethernet
|
10
|
+
|
11
|
+
# Low-level socket creation functionality.
|
12
|
+
module RawSocketFactory
|
13
|
+
# A raw socket sends and receives raw Ethernet frames.
|
14
|
+
#
|
15
|
+
# Args:
|
16
|
+
# eth_device:: device name for the Ethernet card, e.g. 'eth0'
|
17
|
+
# ether_type:: only receive Ethernet frames with this protocol number
|
18
|
+
def self.socket(eth_device = nil, ether_type = nil)
|
19
|
+
ether_type ||= all_ethernet_protocols
|
20
|
+
socket = Socket.new raw_address_family, Socket::SOCK_RAW, htons(ether_type)
|
21
|
+
socket.setsockopt Socket::SOL_SOCKET, Socket::SO_BROADCAST, true
|
22
|
+
set_socket_eth_device(socket, eth_device, ether_type) if eth_device
|
23
|
+
socket
|
24
|
+
end
|
25
|
+
|
26
|
+
class <<self
|
27
|
+
# Sets the Ethernet interface and protocol type for a socket.
|
28
|
+
def set_socket_eth_device(socket, eth_device, ether_type)
|
29
|
+
case RUBY_PLATFORM
|
30
|
+
when /linux/
|
31
|
+
if_number = get_interface_number eth_device
|
32
|
+
# struct sockaddr_ll in /usr/include/linux/if_packet.h
|
33
|
+
socket_address = [raw_address_family, htons(ether_type), if_number,
|
34
|
+
0xFFFF, 0, 0, ""].pack 'SSISCCa8'
|
35
|
+
socket.bind socket_address
|
36
|
+
else
|
37
|
+
raise "Unsupported platform #{RUBY_PLATFORM}"
|
38
|
+
end
|
39
|
+
socket
|
40
|
+
end
|
41
|
+
private :set_socket_eth_device
|
42
|
+
|
43
|
+
# The interface number for an Ethernet interface.
|
44
|
+
def get_interface_number(eth_device)
|
45
|
+
case RUBY_PLATFORM
|
46
|
+
when /linux/
|
47
|
+
# /usr/include/net/if.h, structure ifreq
|
48
|
+
ifreq = [eth_device].pack 'a32'
|
49
|
+
# 0x8933 is SIOCGIFINDEX in /usr/include/bits/ioctls.h
|
50
|
+
socket.ioctl 0x8933, ifreq
|
51
|
+
ifreq[16, 4].unpack('I').first
|
52
|
+
else
|
53
|
+
raise "Unsupported platform #{RUBY_PLATFORM}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
private :get_interface_number
|
57
|
+
|
58
|
+
# The protocol number for listening to all ethernet protocols.
|
59
|
+
def all_ethernet_protocols
|
60
|
+
case RUBY_PLATFORM
|
61
|
+
when /linux/
|
62
|
+
3 # cat /usr/include/linux/if_ether.h | grep ETH_P_ALL
|
63
|
+
else
|
64
|
+
raise "Unsupported platform #{RUBY_PLATFORM}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
private :all_ethernet_protocols
|
68
|
+
|
69
|
+
# The AF / PF number for raw sockets.
|
70
|
+
def raw_address_family
|
71
|
+
case RUBY_PLATFORM
|
72
|
+
when /linux/
|
73
|
+
17 # cat /usr/include/bits/socket.h | grep PF_PACKET
|
74
|
+
when /darwin/
|
75
|
+
18 # cat /usr/include/sys/socket.h | grep AF_LINK
|
76
|
+
else
|
77
|
+
raise "Unsupported platform #{RUBY_PLATFORM}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
private :raw_address_family
|
81
|
+
|
82
|
+
# Converts a 16-bit integer from host-order to network-order.
|
83
|
+
def htons(short_integer)
|
84
|
+
[short_integer].pack('n').unpack('S').first
|
85
|
+
end
|
86
|
+
private :htons
|
87
|
+
end
|
88
|
+
end # module Ethernet::RawSocketFactory
|
89
|
+
|
90
|
+
end # namespace Ethernet
|
91
|
+
|
data/lib/ethernet.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Facade methods for the library.
|
2
|
+
#
|
3
|
+
# See the inner classes for more advanced functionality.
|
4
|
+
module Ethernet
|
5
|
+
# Hash mapping Ethernet device names to their MAC addresses.
|
6
|
+
def self.devices
|
7
|
+
Hash[Ethernet::Devices.all.map { |dev| [dev, Ethernet::Devices.mac(dev)] }]
|
8
|
+
end
|
9
|
+
|
10
|
+
# Ethernet socket that abstracts away frames.
|
11
|
+
#
|
12
|
+
# Args:
|
13
|
+
# eth_device:: device name for the Ethernet card, e.g. 'eth0'
|
14
|
+
# ether_type:: 2-byte Ethernet packet type number
|
15
|
+
def self.socket(eth_device, ether_type)
|
16
|
+
Ethernet::FrameSocket.new eth_device, ether_type
|
17
|
+
end
|
18
|
+
|
19
|
+
# Allow non-root users to create low-level Ethernet sockets.
|
20
|
+
#
|
21
|
+
# This is a security risk, because Ethernet sockets can be used to spy on all
|
22
|
+
# traffic on the machine's network. This should not be called on production
|
23
|
+
# machines.
|
24
|
+
#
|
25
|
+
# Returns true for success, false otherwise. If the call fails, it is most
|
26
|
+
# likely because it is not run by root / Administrator.
|
27
|
+
def self.provision
|
28
|
+
Ethernet::Provisioning.usermode_sockets
|
29
|
+
end
|
30
|
+
|
31
|
+
# A socket that sends and receives raw Ethernet frames.
|
32
|
+
#
|
33
|
+
# Args:
|
34
|
+
# eth_device:: device name for the Ethernet card, e.g. 'eth0'
|
35
|
+
# ether_type:: only receive Ethernet frames with this protocol number
|
36
|
+
def self.raw_socket(eth_device = nil, ether_type = nil)
|
37
|
+
Ethernet::RawSocketFactory.socket eth_device, ether_type
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
require 'ethernet/devices.rb'
|
42
|
+
require 'ethernet/frame_socket.rb'
|
43
|
+
require 'ethernet/provisioning.rb'
|
44
|
+
require 'ethernet/raw_socket_factory.rb'
|
45
|
+
|
46
|
+
|
47
|
+
# TODO(pwnall): move to separate gem
|
48
|
+
require 'ethernet/ping.rb'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Ethernet::Devices do
|
4
|
+
let(:golden_devices) { IfconfigCli.run }
|
5
|
+
let(:golden_active_devices) do
|
6
|
+
golden_devices.keys.select { |device| golden_devices[device][:active] }
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'testing environment' do
|
10
|
+
it 'should have at least one active ethernet device' do
|
11
|
+
golden_active_devices.should have_at_least(1).device
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'all' do
|
16
|
+
let(:devices) { Ethernet::Devices.all }
|
17
|
+
|
18
|
+
it "should find active ethernet devices" do
|
19
|
+
golden_active_devices.each do |device|
|
20
|
+
devices.should include(device)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:eth_device) { IfconfigCli.live_device }
|
26
|
+
let(:mac) { Ethernet::Devices.mac eth_device }
|
27
|
+
|
28
|
+
describe 'mac' do
|
29
|
+
let(:golden_mac) { [golden_devices[eth_device][:mac]].pack('H*') }
|
30
|
+
|
31
|
+
it 'should have 6 bytes' do
|
32
|
+
mac.length.should == 6
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should match ifconfig output' do
|
36
|
+
mac.should == golden_mac
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Ethernet::FrameSocket do
|
4
|
+
let(:eth_device) { IfconfigCli.live_device }
|
5
|
+
let(:eth_type) { 0x0800 }
|
6
|
+
let(:mac) { Ethernet::Devices.mac eth_device }
|
7
|
+
let(:dest_mac) { "\x00\x11\x22\x33\x44\x55" }
|
8
|
+
let(:bcast_mac) { "\xff" * 6 }
|
9
|
+
|
10
|
+
shared_examples_for 'a real socket' do
|
11
|
+
it 'should output a packet' do
|
12
|
+
@socket.send_to dest_mac, "\r\n"
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should receive some network noise' do
|
16
|
+
@socket.recv_from.first.should_not be_empty
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'on eth0' do
|
21
|
+
before { @socket = Ethernet::FrameSocket.new eth_device, eth_type }
|
22
|
+
after { @socket.close }
|
23
|
+
|
24
|
+
it_should_behave_like 'a real socket'
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'from raw socket' do
|
28
|
+
before do
|
29
|
+
raw_socket = Ethernet::RawSocketFactory.socket eth_device, eth_type
|
30
|
+
@socket = Ethernet::FrameSocket.new raw_socket, eth_type, mac
|
31
|
+
end
|
32
|
+
after { @socket.close }
|
33
|
+
|
34
|
+
it_should_behave_like 'a real socket'
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'stubbed' do
|
38
|
+
let(:socket_stub) do
|
39
|
+
RawSocketStub.new([
|
40
|
+
[mac, dest_mac, "\x88\xB7", 'Wrong Ethernet type'].join,
|
41
|
+
[bcast_mac, dest_mac, [eth_type].pack('n'), 'Wrong dest MAC'].join,
|
42
|
+
[mac, bcast_mac, [eth_type].pack('n'), 'Bcast'].join,
|
43
|
+
[mac, dest_mac, [eth_type].pack('n'), 'Correct'].join,
|
44
|
+
])
|
45
|
+
end
|
46
|
+
let(:socket) { Ethernet::FrameSocket.new socket_stub, eth_type, mac }
|
47
|
+
|
48
|
+
shared_examples_for 'after a small send call' do
|
49
|
+
it 'should send a single packet' do
|
50
|
+
socket_stub.sends.length.should == 1
|
51
|
+
end
|
52
|
+
it 'should pad the packet' do
|
53
|
+
socket_stub.sends.first.length.should == 60
|
54
|
+
end
|
55
|
+
it 'should assemble packet correctly in send' do
|
56
|
+
gold = [dest_mac, mac, [eth_type].pack('n'), 'Send data'].join
|
57
|
+
socket_stub.sends.first[0, gold.length].should == gold
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'send_to' do
|
62
|
+
before { socket.send_to dest_mac, 'Send data' }
|
63
|
+
it_should_behave_like 'after a small send call'
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'recv_from' do
|
67
|
+
it 'should filter down to the correct packet' do
|
68
|
+
socket.recv_from.should == ['Bcast', bcast_mac]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'unconnected' do
|
73
|
+
it 'should complain in recv' do
|
74
|
+
lambda { socket.recv }.should raise_error(RuntimeError)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should complain in send' do
|
78
|
+
lambda { socket.send 'Send data' }.should raise_error(RuntimeError)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'connected' do
|
83
|
+
before { socket.connect dest_mac }
|
84
|
+
|
85
|
+
describe 'send' do
|
86
|
+
before { socket.send 'Send data' }
|
87
|
+
it_should_behave_like 'after a small send call'
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'recv' do
|
91
|
+
it 'should filter down to the correct packet' do
|
92
|
+
socket.recv.should == 'Correct'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should delegate close' do
|
98
|
+
socket_stub.should_receive(:close).once
|
99
|
+
socket.close
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Ethernet::RawSocketFactory do
|
4
|
+
let(:eth_device) { IfconfigCli.live_device }
|
5
|
+
let(:mac) { Ethernet::Devices.mac eth_device }
|
6
|
+
|
7
|
+
describe 'socket' do
|
8
|
+
let(:eth_type) { 0x88B7 }
|
9
|
+
|
10
|
+
before { @socket = Ethernet::RawSocketFactory.socket eth_device }
|
11
|
+
after { @socket.close }
|
12
|
+
|
13
|
+
it 'should be able to receive data' do
|
14
|
+
@socket.should respond_to(:recv)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should output a packet' do
|
18
|
+
packet = [mac, mac, [eth_type].pack('n'), "\r\n" * 32].join
|
19
|
+
@socket.send packet, 0
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should receive some network noise' do
|
23
|
+
@socket.recv(8192).should_not be_empty
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/spec/ethernet_spec.rb
CHANGED
@@ -1,7 +1,45 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
describe
|
4
|
-
|
5
|
-
|
3
|
+
describe Ethernet do
|
4
|
+
describe 'provision' do
|
5
|
+
it 'delegates to Provisioning' do
|
6
|
+
Ethernet::Provisioning.should_receive(:usermode_sockets).and_return(:yay)
|
7
|
+
Ethernet.provision.should == :yay
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'devices' do
|
12
|
+
it 'delegates to Devices' do
|
13
|
+
Ethernet::Devices.should_receive(:all).and_return(['yay'])
|
14
|
+
Ethernet::Devices.should_receive(:mac).with('yay').and_return('42')
|
15
|
+
golden = { 'yay' => '42' }
|
16
|
+
Ethernet.devices.should == golden
|
17
|
+
end
|
18
|
+
|
19
|
+
let (:devices) { Ethernet.devices }
|
20
|
+
|
21
|
+
it 'contains at least one device' do
|
22
|
+
devices.keys.should have_at_least(1).name
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'has a MAC for the first device' do
|
26
|
+
devices[devices.keys.first].length.should == 6
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'socket' do
|
31
|
+
it 'delegates to FrameSocket' do
|
32
|
+
Ethernet::FrameSocket.should_receive(:new).with('yay', 1234).
|
33
|
+
and_return(:yay)
|
34
|
+
Ethernet.socket('yay', 1234).should == :yay
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'raw_socket' do
|
39
|
+
it 'delegates to RawSocketFactory' do
|
40
|
+
Ethernet::RawSocketFactory.should_receive(:socket).with('yay', 1234).
|
41
|
+
and_return(:yay)
|
42
|
+
Ethernet.raw_socket('yay', 1234).should == :yay
|
43
|
+
end
|
6
44
|
end
|
7
45
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Wraps ifconfig calls useful for testing.
|
2
|
+
module IfconfigCli
|
3
|
+
# Runs ifconfig and parses its output.
|
4
|
+
def self.run
|
5
|
+
case RUBY_PLATFORM
|
6
|
+
when /win/
|
7
|
+
else
|
8
|
+
output = `ifconfig -a`
|
9
|
+
info_blocks = output.split /\n(?=\w)/
|
10
|
+
Hash[info_blocks.map { |i|
|
11
|
+
name = i.split(' ', 2).first
|
12
|
+
mac = if match = /hwaddr\s([0-9a-f:]+)\s/i.match(i)
|
13
|
+
# Linux ifconfig output.
|
14
|
+
match[1].gsub(':', '').downcase
|
15
|
+
elsif match = /ether\s([0-9a-f:]+)\s/i.match(i)
|
16
|
+
# OSX ifconfig output.
|
17
|
+
match[1].gsub(':', '').downcase
|
18
|
+
elsif match = /\s(([0-9a-f]{2}:){5}[0-9a-f]{2})\s/i.match(i)
|
19
|
+
# First thing that looks like a MAC address.
|
20
|
+
match[1].gsub(':', '').downcase
|
21
|
+
else
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
active = /inet\s/.match(i) ? true : false
|
25
|
+
[name, { :mac => mac, :active => active }]
|
26
|
+
}]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# The name of the first active Ethernet device.
|
31
|
+
#
|
32
|
+
# The return value will most likely be eth0 on Linux and en0 on OSX.
|
33
|
+
def self.live_device
|
34
|
+
run_result = run
|
35
|
+
run_result.keys.sort.find { |device| run_result[device][:active] }
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class RawSocketStub
|
2
|
+
def initialize(recv_data)
|
3
|
+
@packets = recv_data
|
4
|
+
@sends = []
|
5
|
+
end
|
6
|
+
|
7
|
+
def recv(buffer_size)
|
8
|
+
raise 'recv called too many times' if @packets.empty?
|
9
|
+
@packets.shift
|
10
|
+
end
|
11
|
+
|
12
|
+
def send(data, flags)
|
13
|
+
raise 'Weird flags' if flags != 0
|
14
|
+
@sends << data
|
15
|
+
end
|
16
|
+
|
17
|
+
def close
|
18
|
+
@packets = nil
|
19
|
+
@sends = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :sends
|
23
|
+
end
|
metadata
CHANGED
@@ -1,66 +1,121 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ethernet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
4
5
|
prerelease:
|
5
|
-
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
6
11
|
platform: ruby
|
7
12
|
authors:
|
13
|
+
- Victor Costan
|
8
14
|
- HaoQi Li
|
9
15
|
autorequire:
|
10
16
|
bindir: bin
|
11
17
|
cert_chain: []
|
12
18
|
|
13
|
-
date: 2011-
|
14
|
-
default_executable:
|
19
|
+
date: 2011-05-27 00:00:00 Z
|
15
20
|
dependencies:
|
16
21
|
- !ruby/object:Gem::Dependency
|
17
|
-
|
22
|
+
type: :runtime
|
18
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
19
24
|
none: false
|
20
25
|
requirements:
|
21
26
|
- - ~>
|
22
27
|
- !ruby/object:Gem::Version
|
23
|
-
|
24
|
-
|
28
|
+
hash: 25
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
- 1
|
32
|
+
- 1
|
33
|
+
version: 0.1.1
|
25
34
|
prerelease: false
|
26
35
|
version_requirements: *id001
|
36
|
+
name: system-getifaddrs
|
27
37
|
- !ruby/object:Gem::Dependency
|
28
|
-
|
38
|
+
type: :development
|
29
39
|
requirement: &id002 !ruby/object:Gem::Requirement
|
30
40
|
none: false
|
31
41
|
requirements:
|
32
42
|
- - ~>
|
33
43
|
- !ruby/object:Gem::Version
|
34
|
-
|
35
|
-
|
44
|
+
hash: 29
|
45
|
+
segments:
|
46
|
+
- 3
|
47
|
+
- 6
|
48
|
+
- 1
|
49
|
+
version: 3.6.1
|
36
50
|
prerelease: false
|
37
51
|
version_requirements: *id002
|
52
|
+
name: rdoc
|
38
53
|
- !ruby/object:Gem::Dependency
|
39
|
-
|
54
|
+
type: :development
|
40
55
|
requirement: &id003 !ruby/object:Gem::Requirement
|
41
56
|
none: false
|
42
57
|
requirements:
|
43
58
|
- - ~>
|
44
59
|
- !ruby/object:Gem::Version
|
45
|
-
|
46
|
-
|
60
|
+
hash: 23
|
61
|
+
segments:
|
62
|
+
- 2
|
63
|
+
- 6
|
64
|
+
- 0
|
65
|
+
version: 2.6.0
|
47
66
|
prerelease: false
|
48
67
|
version_requirements: *id003
|
68
|
+
name: rspec
|
49
69
|
- !ruby/object:Gem::Dependency
|
50
|
-
|
70
|
+
type: :development
|
51
71
|
requirement: &id004 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 23
|
77
|
+
segments:
|
78
|
+
- 1
|
79
|
+
- 0
|
80
|
+
- 0
|
81
|
+
version: 1.0.0
|
82
|
+
prerelease: false
|
83
|
+
version_requirements: *id004
|
84
|
+
name: bundler
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
type: :development
|
87
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ~>
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
hash: 15
|
93
|
+
segments:
|
94
|
+
- 1
|
95
|
+
- 6
|
96
|
+
- 0
|
97
|
+
version: 1.6.0
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: *id005
|
100
|
+
name: jeweler
|
101
|
+
- !ruby/object:Gem::Dependency
|
102
|
+
type: :development
|
103
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
52
104
|
none: false
|
53
105
|
requirements:
|
54
106
|
- - ">="
|
55
107
|
- !ruby/object:Gem::Version
|
108
|
+
hash: 3
|
109
|
+
segments:
|
110
|
+
- 0
|
56
111
|
version: "0"
|
57
|
-
type: :development
|
58
112
|
prerelease: false
|
59
|
-
version_requirements: *
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
113
|
+
version_requirements: *id006
|
114
|
+
name: rcov
|
115
|
+
description: Provides a Socket-like API that bypasses TCP/IP. Useful for exotic devices and FPGA development.
|
116
|
+
email: victor@costan.us
|
117
|
+
executables:
|
118
|
+
- ethernet_ping
|
64
119
|
extensions: []
|
65
120
|
|
66
121
|
extra_rdoc_files:
|
@@ -68,6 +123,7 @@ extra_rdoc_files:
|
|
68
123
|
- README.rdoc
|
69
124
|
files:
|
70
125
|
- .document
|
126
|
+
- .project
|
71
127
|
- .rspec
|
72
128
|
- Gemfile
|
73
129
|
- Gemfile.lock
|
@@ -75,12 +131,22 @@ files:
|
|
75
131
|
- README.rdoc
|
76
132
|
- Rakefile
|
77
133
|
- VERSION
|
134
|
+
- bin/ethernet_ping
|
78
135
|
- ethernet.gemspec
|
79
136
|
- lib/ethernet.rb
|
137
|
+
- lib/ethernet/devices.rb
|
138
|
+
- lib/ethernet/frame_socket.rb
|
139
|
+
- lib/ethernet/ping.rb
|
140
|
+
- lib/ethernet/provisioning.rb
|
141
|
+
- lib/ethernet/raw_socket_factory.rb
|
142
|
+
- spec/ethernet/devices_spec.rb
|
143
|
+
- spec/ethernet/frame_socket_spec.rb
|
144
|
+
- spec/ethernet/raw_socket_factory_spec.rb
|
80
145
|
- spec/ethernet_spec.rb
|
81
146
|
- spec/spec_helper.rb
|
82
|
-
|
83
|
-
|
147
|
+
- spec/support/ifconfig_cli.rb
|
148
|
+
- spec/support/raw_socket_stub.rb
|
149
|
+
homepage: http://github.com/costan/ethernet
|
84
150
|
licenses:
|
85
151
|
- MIT
|
86
152
|
post_install_message:
|
@@ -93,7 +159,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
159
|
requirements:
|
94
160
|
- - ">="
|
95
161
|
- !ruby/object:Gem::Version
|
96
|
-
hash:
|
162
|
+
hash: 3
|
97
163
|
segments:
|
98
164
|
- 0
|
99
165
|
version: "0"
|
@@ -102,14 +168,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
168
|
requirements:
|
103
169
|
- - ">="
|
104
170
|
- !ruby/object:Gem::Version
|
171
|
+
hash: 3
|
172
|
+
segments:
|
173
|
+
- 0
|
105
174
|
version: "0"
|
106
175
|
requirements: []
|
107
176
|
|
108
177
|
rubyforge_project:
|
109
|
-
rubygems_version: 1.
|
178
|
+
rubygems_version: 1.8.4
|
110
179
|
signing_key:
|
111
180
|
specification_version: 3
|
112
|
-
summary:
|
113
|
-
test_files:
|
114
|
-
|
115
|
-
- spec/spec_helper.rb
|
181
|
+
summary: Ethernet (link-layer level) sockets.
|
182
|
+
test_files: []
|
183
|
+
|