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