rping 0.1.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/README +38 -0
- data/bin/rping +37 -0
- data/lib/rping.rb +154 -0
- metadata +67 -0
data/README
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
= rping
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
rping is a ruby implementation of ping.
|
6
|
+
|
7
|
+
== Source Code
|
8
|
+
|
9
|
+
https://bitbucket.org/winebarrel/rping
|
10
|
+
|
11
|
+
|
12
|
+
== Example
|
13
|
+
=== Command
|
14
|
+
|
15
|
+
shell> rping
|
16
|
+
Usage: rping [options]
|
17
|
+
-c COUNT
|
18
|
+
-i INTERVAL
|
19
|
+
-w TIMEOUT
|
20
|
+
-d DESTINATION
|
21
|
+
shell> rping -c 3 -d localhost
|
22
|
+
PING localhost
|
23
|
+
36 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=128 time=1.0 ms
|
24
|
+
36 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=128 time=0.0 ms
|
25
|
+
36 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=128 time=0.0 ms
|
26
|
+
|
27
|
+
== Library
|
28
|
+
|
29
|
+
require 'lib/rping'
|
30
|
+
|
31
|
+
p RPing.ping('localhost')
|
32
|
+
#=> [{:time=>0.0, :dest=>"127.0.0.1", :src=>"127.0.0.1", :ttl=>128, :size=>36, :seq=>1}]
|
33
|
+
|
34
|
+
RPing.ping('127.0.0.1', :count => 3) do |reply|
|
35
|
+
p reply
|
36
|
+
#=> {:time=>0.0, :src=>"127.0.0.1", :dest=>"127.0.0.1", :ttl=>128, :size=>36, :seq=>1}
|
37
|
+
end
|
38
|
+
|
data/bin/rping
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'lib/rping'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
$stdout.sync = true
|
9
|
+
|
10
|
+
options = {}
|
11
|
+
dest = nil
|
12
|
+
|
13
|
+
ARGV.options do |opt|
|
14
|
+
opt.on('-c COUNT') {|v| options[:count] = v.to_i }
|
15
|
+
opt.on('-i INTERVAL') {|v| options[:interval] = v.to_i }
|
16
|
+
opt.on('-w TIMEOUT') {|v| options[:timeout] = v.to_i }
|
17
|
+
opt.on('-d DESTINATION') {|v| dest = v }
|
18
|
+
|
19
|
+
opt.parse!
|
20
|
+
|
21
|
+
unless dest
|
22
|
+
puts opt.help
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
puts "PING #{dest}"
|
28
|
+
|
29
|
+
RPing.ping(dest, options) do |r|
|
30
|
+
if r
|
31
|
+
puts <<-EOS
|
32
|
+
#{r[:size]} bytes from #{dest} (#{r[:dest]}): icmp_seq=#{r[:seq]} ttl=#{r[:ttl]} time=#{'%.1f' % r[:time]} ms
|
33
|
+
EOS
|
34
|
+
else
|
35
|
+
puts 'packet loss'
|
36
|
+
end
|
37
|
+
end
|
data/lib/rping.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
class RPing
|
5
|
+
MAX_LEN = 64 * 1024
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@count = options.fetch(:count, 1)
|
9
|
+
@interval = options.fetch(:interval, 1)
|
10
|
+
@timeout = options.fetch(:timeout, 4)
|
11
|
+
@icmp_id = Process.pid & 0xffff
|
12
|
+
@seq_num = 1
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.ping(dest, options = {}, &block)
|
16
|
+
self.new(options).ping(dest, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def ping(addr, &block)
|
20
|
+
unless addr =~ /\A\d{3}\.\d{3}\.\d{3}\.\d{3}\Z/
|
21
|
+
addr = IPSocket.getaddress(addr)
|
22
|
+
end
|
23
|
+
|
24
|
+
sock = nil
|
25
|
+
buf = []
|
26
|
+
|
27
|
+
begin
|
28
|
+
sock = make_socket
|
29
|
+
th = ping_recv(sock, buf, &block)
|
30
|
+
ping_send(sock, addr)
|
31
|
+
th.join
|
32
|
+
ensure
|
33
|
+
sock.close if sock
|
34
|
+
end
|
35
|
+
|
36
|
+
return buf
|
37
|
+
end
|
38
|
+
|
39
|
+
def make_socket
|
40
|
+
Socket.new(Socket::AF_INET, Socket::SOCK_RAW, Socket::IPPROTO_ICMP)
|
41
|
+
end
|
42
|
+
|
43
|
+
def ping_send(sock, addr)
|
44
|
+
sockaddr = Socket.pack_sockaddr_in(0, addr)
|
45
|
+
|
46
|
+
@count.times do |i|
|
47
|
+
sleep @interval unless i.zero?
|
48
|
+
req = make_echo_request
|
49
|
+
sock.send(req, 0, sockaddr)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def ping_recv(sock, buf = nil, &block)
|
54
|
+
Thread.start do
|
55
|
+
@count.times do
|
56
|
+
reply = ping_recv0(sock)
|
57
|
+
yield(reply) if block
|
58
|
+
buf << reply if buf
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def ping_recv0(sock)
|
65
|
+
reply = nil
|
66
|
+
|
67
|
+
begin
|
68
|
+
timeout(@timeout) do
|
69
|
+
if select([sock], nil, nil, @timeout)
|
70
|
+
msg = sock.recv(MAX_LEN)
|
71
|
+
recv_time = Time.now.to_f
|
72
|
+
ip, icmp = unpack_echo_reply(msg)
|
73
|
+
|
74
|
+
# icmp[0] == 0: Type == Echo Reply
|
75
|
+
if icmp[0] == 0 and icmp[3] == @icmp_id
|
76
|
+
reply = {
|
77
|
+
:dest => ip[8].bytes.to_a.join('.'),
|
78
|
+
:src => ip[9].bytes.to_a.join('.'),
|
79
|
+
:size => msg.length,
|
80
|
+
:ttl => ip[5],
|
81
|
+
:seq => icmp[4],
|
82
|
+
:time => (recv_time - icmp[5]) * 1000,
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
rescue Timeout::Error
|
88
|
+
end
|
89
|
+
|
90
|
+
return reply
|
91
|
+
end
|
92
|
+
|
93
|
+
def make_echo_request
|
94
|
+
data = Time.now.to_f
|
95
|
+
|
96
|
+
req = [
|
97
|
+
[ 8, :C], # Type = Echo
|
98
|
+
[ 0, :C], # Code = 0
|
99
|
+
[ 0, :n], # Checksum
|
100
|
+
[@icmp_id, :n], # Identification
|
101
|
+
[@seq_num, :n], # Sequence Number
|
102
|
+
[ data, :d], # Data
|
103
|
+
]
|
104
|
+
|
105
|
+
@seq_num += 1
|
106
|
+
req = req.map {|i| i[0] }.pack(req.map {|i| i[1] }.join)
|
107
|
+
update_checksum(req)
|
108
|
+
|
109
|
+
return req
|
110
|
+
end
|
111
|
+
|
112
|
+
def update_checksum(buf)
|
113
|
+
sum = 0
|
114
|
+
buf.unpack('n*').each {|i| sum += i }
|
115
|
+
|
116
|
+
unless (buf.length % 2).zero?
|
117
|
+
sum += buf[-1].unpack('n')[0]
|
118
|
+
end
|
119
|
+
|
120
|
+
sum = (sum & 0xffff) + (sum >> 16);
|
121
|
+
sum = (sum & 0xffff) + (sum >> 16);
|
122
|
+
|
123
|
+
buf[2, 2] = [~sum & 0xffff].pack('n')
|
124
|
+
end
|
125
|
+
|
126
|
+
def unpack_echo_reply(buf)
|
127
|
+
tmpl = [
|
128
|
+
# IP
|
129
|
+
:C, # Version, IHL
|
130
|
+
:C, # Type of Service
|
131
|
+
:n, # Total Length
|
132
|
+
:n, # Identification
|
133
|
+
:n, # Flags, Fragment Offset
|
134
|
+
:C, # Time to Live,
|
135
|
+
:C, # Protocol
|
136
|
+
:n, # Header Checksum
|
137
|
+
:a4, # Source Address
|
138
|
+
:a4, # Destination Address
|
139
|
+
# ICMP
|
140
|
+
:C, # Type
|
141
|
+
:C, # Code
|
142
|
+
:n, # Checksum
|
143
|
+
:n, # Identification
|
144
|
+
:n, # Sequence Number
|
145
|
+
:d, # Data
|
146
|
+
]
|
147
|
+
|
148
|
+
reply = buf.unpack(tmpl.join)
|
149
|
+
ip = reply.slice(0, 19)
|
150
|
+
icmp = reply.slice(10, 6)
|
151
|
+
|
152
|
+
return [ip, icmp]
|
153
|
+
end
|
154
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rping
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- winebarrel
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-01-21 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email: sgwr_dts@yahoo.co.jp
|
23
|
+
executables:
|
24
|
+
- rping
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- README
|
31
|
+
- bin/rping
|
32
|
+
- lib/rping.rb
|
33
|
+
homepage: https://bitbucket.org/winebarrel/rping
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: 3
|
47
|
+
segments:
|
48
|
+
- 0
|
49
|
+
version: "0"
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
hash: 3
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.8.11
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: rping is a ruby implementation of ping.
|
66
|
+
test_files: []
|
67
|
+
|