ether_ping 0.2.0 → 0.3.0
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/Gemfile +1 -1
- data/Gemfile.lock +3 -3
- data/README.rdoc +5 -7
- data/VERSION +1 -1
- data/bin/ether_ping +47 -26
- data/bin/ether_ping_server +32 -15
- data/ether_ping.gemspec +3 -5
- data/lib/ether_ping/client.rb +17 -9
- data/lib/ether_ping/server.rb +15 -30
- metadata +4 -6
- data/spec/ether_ping_spec.rb +0 -7
- data/spec/spec_helper.rb +0 -12
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -2,8 +2,9 @@ GEM
|
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
4
|
diff-lcs (1.1.2)
|
5
|
-
ethernet (0.1.
|
6
|
-
|
5
|
+
ethernet (0.1.2)
|
6
|
+
ffi (>= 1.0.0)
|
7
|
+
ffi (1.0.9)
|
7
8
|
git (1.2.5)
|
8
9
|
jeweler (1.6.0)
|
9
10
|
bundler (~> 1.0.0)
|
@@ -20,7 +21,6 @@ GEM
|
|
20
21
|
rspec-expectations (2.6.0)
|
21
22
|
diff-lcs (~> 1.1.2)
|
22
23
|
rspec-mocks (2.6.0)
|
23
|
-
system-getifaddrs (0.1.1)
|
24
24
|
|
25
25
|
PLATFORMS
|
26
26
|
ruby
|
data/README.rdoc
CHANGED
@@ -8,16 +8,14 @@ While ping uses an echo service embedded in every TCP/IP stack, ether_ping
|
|
8
8
|
relies on a server program to have its frames echoed. First start the server on
|
9
9
|
the destination computer, and tell it what Ethernet device it should listen to.
|
10
10
|
|
11
|
-
ether_ping_server eth0 # on Linux
|
12
|
-
ether_ping_server en0 # on Mac OS
|
11
|
+
ether_ping_server -e eth0 # on Linux
|
12
|
+
ether_ping_server -e en0 # on Mac OS
|
13
13
|
|
14
|
-
Then launch the ping utility.
|
15
|
-
* the Ethernet device that will be used for sending ping frames
|
16
|
-
* the MAC of the destination's Ethernet device
|
17
|
-
* the data to be sent
|
14
|
+
Then launch the ping utility.
|
18
15
|
|
19
|
-
ether_ping eth0 c42c0337fffc
|
16
|
+
ether_ping -e eth0 c42c0337fffc
|
20
17
|
|
18
|
+
Both commands accept the -h / --help option.
|
21
19
|
|
22
20
|
== Contributing to ether_ping
|
23
21
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/bin/ether_ping
CHANGED
@@ -1,41 +1,62 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
|
2
4
|
require 'rubygems'
|
3
5
|
require 'ether_ping'
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
Usage: #{$0}
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
options = {}
|
8
|
+
parser = OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: #{$0} [options] destination_mac"
|
10
|
+
|
11
|
+
opts.on('-e', '--interface ETH', 'Ethernet interface name, e.g. eth0') do |i|
|
12
|
+
options[:interface] = i
|
13
|
+
end
|
14
|
+
|
15
|
+
opts.on('-t', '--type TYPE',
|
16
|
+
'Ethernet II frame type, as 2 hex bytes, e.g. 0800 for IP') do |p|
|
17
|
+
options[:ether_type] = [p].pack('H*').unpack('n').first
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on('-d', '--data HEXBYTES',
|
21
|
+
'Ping packet data, in a sequence of hexadecimal bytes') do |d|
|
22
|
+
options[:data] = [d].pack('H*')
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on('-s', '--size SIZE', 'Number of bytes in a ping packet') do |s|
|
26
|
+
options[:size] = s.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on('-h', '--help', 'Display this screen') do
|
30
|
+
puts opts
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
parser.parse!
|
36
|
+
options[:interface] ||= Ethernet.devices.keys.sort.first
|
37
|
+
options[:ether_type] ||= 0x88B5
|
38
|
+
options[:size] ||= 64 unless options[:data]
|
12
39
|
|
13
|
-
|
14
|
-
|
15
|
-
END_USAGE
|
40
|
+
if ARGV.length < 1
|
41
|
+
puts "Missing destination MAC address"
|
16
42
|
exit 1
|
17
43
|
end
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
data = [ARGV[2]].pack('H*')
|
24
|
-
else
|
25
|
-
ether_type_string = ARGV[2]
|
26
|
-
data = [ARGV[3]].pack('H*')
|
27
|
-
end
|
28
|
-
ether_type = [ether_type_string].pack('H*').unpack('n').first
|
44
|
+
destination_mac = ARGV.first
|
45
|
+
|
46
|
+
print "Pinging #{destination_mac} on #{options[:interface]} "
|
47
|
+
print "with a #{options[:size] || options[:data].length}-byte frame "
|
48
|
+
print "of type #{'%04X' % options[:ether_type]}\n"
|
29
49
|
|
30
|
-
client = EtherPing::Client.new interface, ether_type,
|
50
|
+
client = EtherPing::Client.new options[:interface], options[:ether_type],
|
51
|
+
destination_mac
|
31
52
|
|
32
53
|
loop do
|
33
|
-
print "
|
54
|
+
print "Ping... "
|
34
55
|
STDOUT.flush
|
35
|
-
result = client.ping data
|
56
|
+
result = client.ping options[:size] || options[:data]
|
36
57
|
if result
|
37
|
-
if result
|
38
|
-
puts "
|
58
|
+
if result.kind_of? Numeric
|
59
|
+
puts "#{result * 1000000}us"
|
39
60
|
else
|
40
61
|
puts "Failed"
|
41
62
|
puts "Expected:\n#{result.first.unpack('H*').first}"
|
data/bin/ether_ping_server
CHANGED
@@ -1,22 +1,39 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
|
2
4
|
require 'rubygems'
|
3
5
|
require 'ether_ping'
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
Usage: #{$0}
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
options = { :verbose => true }
|
8
|
+
parser = OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: #{$0} [options]"
|
10
|
+
|
11
|
+
opts.on('-e', '--interface ETH', 'Ethernet interface name, e.g. eth0') do |i|
|
12
|
+
options[:interface] = i
|
13
|
+
end
|
14
|
+
|
15
|
+
opts.on('-t', '--type TYPE',
|
16
|
+
'Ethernet II frame type, as 2 hex bytes, e.g. 0800 for IP') do |p|
|
17
|
+
options[:ether_type] = [p].pack('H*').unpack('n').first
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on('-s', '--silent', 'Do not display packets as they come in') do
|
21
|
+
options[:verbose] = false
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on('-h', '--help', 'Display this screen') do
|
25
|
+
puts opts
|
26
|
+
exit
|
27
|
+
end
|
16
28
|
end
|
17
|
-
|
18
|
-
interface = ARGV[0]
|
19
|
-
ether_type = [ARGV[1] || '88B5'].pack('H*').unpack('n').first
|
20
29
|
|
21
|
-
|
30
|
+
parser.parse!
|
31
|
+
options[:interface] ||= Ethernet.devices.keys.sort.first
|
32
|
+
options[:ether_type] ||= 0x88B5
|
33
|
+
interface_mac = Ethernet::Devices.mac(options[:interface]).unpack('H*').first
|
34
|
+
|
35
|
+
print "Waiting for frames of type #{'%04X' % options[:ether_type]} "
|
36
|
+
print "on #{options[:interface]} with MAC #{interface_mac}\n"
|
37
|
+
ping_server = EtherPing::Server.new options[:interface], options[:ether_type],
|
38
|
+
options[:verbose]
|
22
39
|
ping_server.run
|
data/ether_ping.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ether_ping}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{Victor Costan}]
|
12
|
-
s.date = %q{2011-05-
|
12
|
+
s.date = %q{2011-05-30}
|
13
13
|
s.description = %q{Contains an Ethernet-level ping server and client.}
|
14
14
|
s.email = %q{victor@costan.us}
|
15
15
|
s.executables = [%q{ether_ping_server}, %q{ether_ping}]
|
@@ -32,9 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
"ether_ping.gemspec",
|
33
33
|
"lib/ether_ping.rb",
|
34
34
|
"lib/ether_ping/client.rb",
|
35
|
-
"lib/ether_ping/server.rb"
|
36
|
-
"spec/ether_ping_spec.rb",
|
37
|
-
"spec/spec_helper.rb"
|
35
|
+
"lib/ether_ping/server.rb"
|
38
36
|
]
|
39
37
|
s.homepage = %q{http://github.com/pwnall/ether_ping}
|
40
38
|
s.licenses = [%q{MIT}]
|
data/lib/ether_ping/client.rb
CHANGED
@@ -18,28 +18,36 @@ class Client
|
|
18
18
|
|
19
19
|
# Pings over raw Ethernet sockets.
|
20
20
|
#
|
21
|
-
# Returns
|
22
|
-
# received] strings if it doesn't
|
21
|
+
# Returns a Number representing the ping latency (in seconds) if the ping
|
22
|
+
# response matches, an array of [expected, received] strings if it doesn't
|
23
|
+
# match, and false if the ping times out.
|
23
24
|
def ping(data, timeout = 1)
|
24
|
-
|
25
|
+
if data.kind_of? Numeric
|
26
|
+
data = "\0" * data
|
27
|
+
end
|
25
28
|
# Pad data to have at least 64 bytes.
|
26
29
|
data += "\0" * (64 - data.length) if data.length < 64
|
27
30
|
|
28
|
-
ping_packet = @dest_mac
|
29
|
-
@socket.send ping_packet, 0
|
31
|
+
ping_packet = [@dest_mac, @source_mac, @ether_type, data].join
|
30
32
|
|
31
|
-
response_packet = @source_mac + @dest_mac + @ether_type + data
|
32
|
-
|
33
33
|
response = nil
|
34
|
+
receive_ts = nil
|
35
|
+
send_ts = nil
|
34
36
|
begin
|
35
37
|
Timeout.timeout timeout do
|
36
|
-
|
38
|
+
send_ts = Time.now
|
39
|
+
@socket.send ping_packet, 0
|
40
|
+
response = @socket.recv ping_packet.length * 2
|
41
|
+
receive_ts = Time.now
|
37
42
|
end
|
38
43
|
rescue Timeout::Error
|
39
44
|
response = nil
|
40
45
|
end
|
41
46
|
return false unless response
|
42
|
-
|
47
|
+
|
48
|
+
response_packet = [@source_mac, @dest_mac, @ether_type, data].join
|
49
|
+
response == response_packet ? receive_ts - send_ts :
|
50
|
+
[response, response_packet]
|
43
51
|
end
|
44
52
|
end # module EtherPing::Client
|
45
53
|
|
data/lib/ether_ping/server.rb
CHANGED
@@ -7,43 +7,28 @@ module EtherPing
|
|
7
7
|
|
8
8
|
# Responder for ping utility using raw Ethernet sockets.
|
9
9
|
class Server
|
10
|
-
module Connection
|
11
|
-
def receive_data(packet)
|
12
|
-
dest_mac = packet[0, 6].unpack('H*')
|
13
|
-
source_mac = packet[6, 6].unpack('H*')
|
14
|
-
ether_type = packet[12, 2].unpack('H*')
|
15
|
-
|
16
|
-
puts "Src: #{source_mac} Dst: #{dest_mac} Eth: #{ether_type}\n"
|
17
|
-
puts packet[14..-1].unpack('H*')
|
18
|
-
|
19
|
-
# Exchange the source and destination MAC addresses.
|
20
|
-
packet[0, 6], packet[6, 6] = packet[6, 6], packet[0, 6]
|
21
|
-
send_data packet
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class ConnectionWrapper
|
26
|
-
include Connection
|
27
|
-
|
28
|
-
def initialize(socket)
|
29
|
-
@socket = socket
|
30
|
-
end
|
31
|
-
|
32
|
-
def send_data(data)
|
33
|
-
@socket.send data, 0
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
10
|
def run
|
38
|
-
connection = ConnectionWrapper.new @socket
|
39
11
|
loop do
|
40
12
|
packet = @socket.recv 65536
|
41
|
-
|
13
|
+
# Respond afap: exchange the source and destination MAC addresses.
|
14
|
+
packet[0, 6], packet[6, 6] = packet[6, 6], packet[0, 6]
|
15
|
+
@socket.send packet, 0
|
16
|
+
|
17
|
+
if @verbose
|
18
|
+
# The MAC addresses were switched above, before responding.
|
19
|
+
dest_mac = packet[6, 6].unpack('H*').first
|
20
|
+
source_mac = packet[0, 6].unpack('H*').first
|
21
|
+
ether_type = packet[12, 2].unpack('H*').first
|
22
|
+
|
23
|
+
puts "Src: #{source_mac} Dst: #{dest_mac} Eth: #{ether_type} Data:\n"
|
24
|
+
puts packet[14..-1].unpack('H*').first
|
25
|
+
end
|
42
26
|
end
|
43
27
|
end
|
44
28
|
|
45
|
-
def initialize(eth_device, ether_type)
|
29
|
+
def initialize(eth_device, ether_type, verbose = true)
|
46
30
|
@socket = Ethernet.raw_socket eth_device, ether_type
|
31
|
+
@verbose = verbose
|
47
32
|
end
|
48
33
|
end # module EtherPing::Server
|
49
34
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ether_ping
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Victor Costan
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-30 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
type: :runtime
|
@@ -137,8 +137,6 @@ files:
|
|
137
137
|
- lib/ether_ping.rb
|
138
138
|
- lib/ether_ping/client.rb
|
139
139
|
- lib/ether_ping/server.rb
|
140
|
-
- spec/ether_ping_spec.rb
|
141
|
-
- spec/spec_helper.rb
|
142
140
|
homepage: http://github.com/pwnall/ether_ping
|
143
141
|
licenses:
|
144
142
|
- MIT
|
data/spec/ether_ping_spec.rb
DELETED
data/spec/spec_helper.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
-
require 'rspec'
|
4
|
-
require 'ether_ping'
|
5
|
-
|
6
|
-
# Requires supporting files with custom matchers and macros, etc,
|
7
|
-
# in ./support/ and its subdirectories.
|
8
|
-
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
-
|
10
|
-
RSpec.configure do |config|
|
11
|
-
|
12
|
-
end
|