simple_ping 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.ruby-version +1 -0
- data/README.md +18 -2
- data/lib/simple_ping/client.rb +10 -12
- data/lib/simple_ping/icmp.rb +1 -1
- data/lib/simple_ping/version.rb +1 -1
- data/sig/simple_ping.rbs +94 -0
- metadata +8 -9
- data/client.rb +0 -91
- data/icmp.rb +0 -132
- data/recv_message.rb +0 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c99b16f604de38384de5e722a9493406a59ccf56891d68a6abc99e91b42673c9
|
4
|
+
data.tar.gz: b06fd1a5ffaeaec507a8236ff475e78def4af9c5e6ad32e17831bfcac8af58eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73fec53bfc6bc75af1a583726413ec13f9d135f9d7e7e43f9ea9c5987bbf8e39a1a0f266d2d89f1326f5a8bf46dec9c361aa56fc66431b212a75b424f6c62043
|
7
|
+
data.tar.gz: ec5f43516e4ce018ca5e5228ed56380ffbe120e636f789ddbe39146a05095062676d660a5632e5c2653f0ffd7fd4415a07beca0b71aa0abc7a878e3c58152330
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.0.0
|
data/README.md
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
# Overview
|
2
|
-
A Simpe Ping Client for Ruby.
|
2
|
+
A Simpe Ping(ICMP) Client for Ruby.
|
3
|
+
https://rubygems.org/gems/simple_ping
|
3
4
|
|
4
5
|
# How to use
|
5
6
|
※ Need root privileges to run.
|
6
7
|
|
7
|
-
```
|
8
|
+
```ruby
|
9
|
+
require "simple_ping"
|
10
|
+
|
8
11
|
ping_client = SimplePing::Client.new(src_ip_addr: "192.168.1.100")
|
9
12
|
ping_client.exec(dest_ip_addr: "192.168.1.101")
|
10
13
|
```
|
@@ -16,5 +19,18 @@ ping_client.exec(dest_ip_addr: "192.168.1.101")
|
|
16
19
|
- Does not support retries
|
17
20
|
- Confirmed the operation with Ruby 2.7.1
|
18
21
|
|
22
|
+
|
23
|
+
# What you can do
|
24
|
+
|
25
|
+
- Return the success or failure of the ping (ICMP) result with true/false
|
26
|
+
- Destination is IP address
|
27
|
+
|
28
|
+
# What you can not do now
|
29
|
+
|
30
|
+
- Addressing by FQDN
|
31
|
+
- Retry
|
32
|
+
- Customized transmission data (ID specification, data section specification, etc.)
|
33
|
+
- Etc., etc
|
34
|
+
|
19
35
|
# License
|
20
36
|
MIT
|
data/lib/simple_ping/client.rb
CHANGED
@@ -40,19 +40,17 @@ class SimplePing::Client
|
|
40
40
|
# Receive
|
41
41
|
begin
|
42
42
|
Timeout.timeout(TIMEOUT_TIME) do
|
43
|
-
|
44
|
-
|
45
|
-
icmp_reply = SimplePing::RecvMessage.new(mesg).to_icmp
|
43
|
+
mesg, _ = socket.recvfrom(1500)
|
44
|
+
icmp_reply = SimplePing::RecvMessage.new(mesg).to_icmp
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
46
|
+
if icmp.successful_reply?(icmp_reply)
|
47
|
+
true
|
48
|
+
elsif icmp_reply.is_type_destination_unreachable?
|
49
|
+
logger.warn { "Destination Unreachable!!" }
|
50
|
+
false
|
51
|
+
elsif icmp_reply.is_type_redirect?
|
52
|
+
logger.warn { "Redirect Required!!" }
|
53
|
+
false
|
56
54
|
end
|
57
55
|
end
|
58
56
|
rescue Timeout::Error => e
|
data/lib/simple_ping/icmp.rb
CHANGED
@@ -64,7 +64,7 @@ class SimplePing::ICMP
|
|
64
64
|
@seq_number.to_s(2).rjust(16, "0")
|
65
65
|
|
66
66
|
data_byte_arr = bynary_data.scan(/.{1,8}/)
|
67
|
-
data_byte_arr.map! { |byte| byte.to_i(2).chr }
|
67
|
+
data_byte_arr.map! { |byte| byte.to_i(2).chr } # TO ASCII
|
68
68
|
data_byte_arr.join + @data
|
69
69
|
end
|
70
70
|
|
data/lib/simple_ping/version.rb
CHANGED
data/sig/simple_ping.rbs
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module SimplePing
|
2
|
+
end
|
3
|
+
|
4
|
+
class SimplePing::Client
|
5
|
+
public
|
6
|
+
|
7
|
+
def exec: (dest_ip_addr: untyped, ?data: untyped) -> untyped
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def initialize: (src_ip_addr: String, ?log_level: Integer) -> void
|
12
|
+
|
13
|
+
def logger: () -> untyped
|
14
|
+
|
15
|
+
def socket: () -> untyped
|
16
|
+
end
|
17
|
+
|
18
|
+
SimplePing::Client::TIMEOUT_TIME: Integer
|
19
|
+
|
20
|
+
class SimplePing::ICMP
|
21
|
+
public
|
22
|
+
|
23
|
+
def data: () -> untyped
|
24
|
+
|
25
|
+
def data=: (untyped) -> untyped
|
26
|
+
|
27
|
+
def id: () -> untyped
|
28
|
+
|
29
|
+
def id=: (untyped) -> untyped
|
30
|
+
|
31
|
+
def is_type_destination_unreachable?: () -> untyped
|
32
|
+
|
33
|
+
def is_type_echo?: () -> untyped
|
34
|
+
|
35
|
+
def is_type_echo_reply?: () -> untyped
|
36
|
+
|
37
|
+
def is_type_redirect?: () -> untyped
|
38
|
+
|
39
|
+
def seq_number: () -> untyped
|
40
|
+
|
41
|
+
def seq_number=: (untyped) -> untyped
|
42
|
+
|
43
|
+
def successful_reply?: (untyped icmp) -> untyped
|
44
|
+
|
45
|
+
def to_trans_data: () -> untyped
|
46
|
+
|
47
|
+
def type: () -> untyped
|
48
|
+
|
49
|
+
def type=: (untyped) -> untyped
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def carry_up: (untyped num) -> untyped
|
54
|
+
|
55
|
+
def checksum: () -> untyped
|
56
|
+
|
57
|
+
def gen_data: () -> untyped
|
58
|
+
|
59
|
+
def gen_id: () -> untyped
|
60
|
+
|
61
|
+
def gen_seq_number: () -> untyped
|
62
|
+
|
63
|
+
def initialize: (type: untyped, ?code: untyped, ?id: untyped, ?seq_number: untyped, ?data: untyped) -> untyped
|
64
|
+
end
|
65
|
+
|
66
|
+
SimplePing::ICMP::TYPE_ICMP_DESTINATION_UNREACHABLE: Integer
|
67
|
+
|
68
|
+
SimplePing::ICMP::TYPE_ICMP_ECHO_REPLY: Integer
|
69
|
+
|
70
|
+
SimplePing::ICMP::TYPE_ICMP_ECHO_REQUEST: Integer
|
71
|
+
|
72
|
+
SimplePing::ICMP::TYPE_ICMP_REDIRECT: Integer
|
73
|
+
|
74
|
+
class SimplePing::RecvMessage
|
75
|
+
public
|
76
|
+
|
77
|
+
def code: () -> untyped
|
78
|
+
|
79
|
+
def data: () -> untyped
|
80
|
+
|
81
|
+
def id: () -> untyped
|
82
|
+
|
83
|
+
def seq_number: () -> untyped
|
84
|
+
|
85
|
+
def to_icmp: () -> untyped
|
86
|
+
|
87
|
+
def type: () -> untyped
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def initialize: (untyped mesg) -> untyped
|
92
|
+
end
|
93
|
+
|
94
|
+
SimplePing::VERSION: String
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_ping
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akira Kure
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -61,6 +61,7 @@ extra_rdoc_files: []
|
|
61
61
|
files:
|
62
62
|
- ".gitignore"
|
63
63
|
- ".rspec"
|
64
|
+
- ".ruby-version"
|
64
65
|
- ".travis.yml"
|
65
66
|
- CODE_OF_CONDUCT.md
|
66
67
|
- Gemfile
|
@@ -69,14 +70,12 @@ files:
|
|
69
70
|
- Rakefile
|
70
71
|
- bin/console
|
71
72
|
- bin/setup
|
72
|
-
- client.rb
|
73
|
-
- icmp.rb
|
74
73
|
- lib/simple_ping.rb
|
75
74
|
- lib/simple_ping/client.rb
|
76
75
|
- lib/simple_ping/icmp.rb
|
77
76
|
- lib/simple_ping/recv_message.rb
|
78
77
|
- lib/simple_ping/version.rb
|
79
|
-
-
|
78
|
+
- sig/simple_ping.rbs
|
80
79
|
- simple_ping.gemspec
|
81
80
|
homepage: https://github.com/kuredev/simple_ping
|
82
81
|
licenses:
|
@@ -84,7 +83,7 @@ licenses:
|
|
84
83
|
metadata:
|
85
84
|
homepage_uri: https://github.com/kuredev/simple_ping
|
86
85
|
source_code_uri: https://github.com/kuredev/simple_ping
|
87
|
-
post_install_message:
|
86
|
+
post_install_message:
|
88
87
|
rdoc_options: []
|
89
88
|
require_paths:
|
90
89
|
- lib
|
@@ -99,8 +98,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
98
|
- !ruby/object:Gem::Version
|
100
99
|
version: '0'
|
101
100
|
requirements: []
|
102
|
-
rubygems_version: 3.
|
103
|
-
signing_key:
|
101
|
+
rubygems_version: 3.2.3
|
102
|
+
signing_key:
|
104
103
|
specification_version: 4
|
105
104
|
summary: A Simpe Ping Client for Ruby.
|
106
105
|
test_files: []
|
data/client.rb
DELETED
@@ -1,91 +0,0 @@
|
|
1
|
-
require "logger"
|
2
|
-
require "socket"
|
3
|
-
require "timeout"
|
4
|
-
require_relative "recv_message"
|
5
|
-
require_relative "icmp"
|
6
|
-
|
7
|
-
# Simple Ping (ICMP) client
|
8
|
-
# Root privilege required to run
|
9
|
-
# ex)
|
10
|
-
# require_relative "./simple_ping/client"
|
11
|
-
#
|
12
|
-
# client = SimplePing::Client.new(src_ip_addr: "192.168.1.100")
|
13
|
-
# client.exec(dest_ip_addr: "192.168.1.101") # => true or false
|
14
|
-
module SimplePing
|
15
|
-
class Client
|
16
|
-
# Wait time for ICMP Reply
|
17
|
-
TIMEOUT_TIME = 10
|
18
|
-
|
19
|
-
# constructor
|
20
|
-
#
|
21
|
-
# @param src_ip_addr [String] IP address of the interface to send ping, ex: "192.168.1.100"
|
22
|
-
def initialize(src_ip_addr:, log_level: Logger::INFO)
|
23
|
-
@src_ip_addr = src_ip_addr
|
24
|
-
@log_level = log_level
|
25
|
-
end
|
26
|
-
|
27
|
-
# Execute ping(ICMP).
|
28
|
-
# Basically, it returns Boolean depending on the result.
|
29
|
-
# Exception may be thrown due to unexpected error etc.
|
30
|
-
#
|
31
|
-
# @param dest_ip_addr [String] IP address of destination to send ping, ex: "192.168.1.101"
|
32
|
-
# @param data [String] ICMP Datagram, ex: "abc"
|
33
|
-
# @return [Boolean]
|
34
|
-
def exec(dest_ip_addr:, data: nil)
|
35
|
-
# Transmission
|
36
|
-
icmp = ICMP.new(type: ICMP::TYPE_ICMP_ECHO_REQUEST, data: data)
|
37
|
-
sockaddr = Socket.sockaddr_in(nil, dest_ip_addr)
|
38
|
-
trans_data = icmp.to_trans_data
|
39
|
-
socket.send(trans_data, 0, sockaddr)
|
40
|
-
|
41
|
-
# Receive
|
42
|
-
begin
|
43
|
-
Timeout.timeout(TIMEOUT_TIME) do
|
44
|
-
loop do
|
45
|
-
mesg, _ = socket.recvfrom(1500)
|
46
|
-
icmp_reply = RecvMessage.new(mesg).to_icmp
|
47
|
-
|
48
|
-
if icmp.successful_reply?(icmp_reply)
|
49
|
-
return true
|
50
|
-
elsif icmp_reply.is_type_destination_unreachable?
|
51
|
-
logger.warn { "Destination Unreachable!!" }
|
52
|
-
return false
|
53
|
-
elsif icmp_reply.is_type_redirect?
|
54
|
-
logger.warn { "Redirect Required!!" }
|
55
|
-
return false
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
rescue Timeout::Error => e
|
60
|
-
logger.warn { "Timeout Occurred! #{e}" }
|
61
|
-
false
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
# @return [Logger]
|
68
|
-
def logger
|
69
|
-
@logger ||= begin
|
70
|
-
logger = Logger.new(STDOUT)
|
71
|
-
logger.level = @log_level
|
72
|
-
logger
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Socket instance
|
77
|
-
#
|
78
|
-
# @return [Socket]
|
79
|
-
def socket
|
80
|
-
@socket ||= begin
|
81
|
-
socket = Socket.open(
|
82
|
-
Socket::AF_INET, # IPv4
|
83
|
-
Socket::SOCK_RAW, # RAW Socket
|
84
|
-
Socket::IPPROTO_ICMP # ICMP
|
85
|
-
)
|
86
|
-
socket.bind(Socket.sockaddr_in(nil, @src_ip_addr))
|
87
|
-
socket
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
data/icmp.rb
DELETED
@@ -1,132 +0,0 @@
|
|
1
|
-
module SimplePing
|
2
|
-
class ICMP
|
3
|
-
attr_accessor :id, :seq_number, :data, :type
|
4
|
-
|
5
|
-
# ICMP TYPES
|
6
|
-
TYPE_ICMP_ECHO_REPLY = 0x00
|
7
|
-
TYPE_ICMP_DESTINATION_UNREACHABLE = 0x03
|
8
|
-
TYPE_ICMP_REDIRECT = 0x05
|
9
|
-
TYPE_ICMP_ECHO_REQUEST = 0x08
|
10
|
-
|
11
|
-
# constructor
|
12
|
-
#
|
13
|
-
# @param code [Integer] 0x01
|
14
|
-
# @param type [Integer] 0x01
|
15
|
-
# @param id [Integer] 0x01
|
16
|
-
# @param seq_number [Integer] 0x01
|
17
|
-
# @param data [String] 0x01
|
18
|
-
def initialize(type:, code: 0, id: nil, seq_number: nil, data: nil)
|
19
|
-
@type = type
|
20
|
-
@code = code
|
21
|
-
@id = id || gen_id
|
22
|
-
@seq_number = seq_number || gen_seq_number
|
23
|
-
@data = data || gen_data
|
24
|
-
@checksum = checksum
|
25
|
-
end
|
26
|
-
|
27
|
-
# @return [Boolean]
|
28
|
-
def is_type_redirect?
|
29
|
-
@type == TYPE_ICMP_REDIRECT
|
30
|
-
end
|
31
|
-
|
32
|
-
# @return [Boolean]
|
33
|
-
def is_type_echo?
|
34
|
-
@type == TYPE_ICMP_ECHO_REPLY || @type == TYPE_ICMP_ECHO_REQUEST
|
35
|
-
end
|
36
|
-
|
37
|
-
# @return [Boolean]
|
38
|
-
def is_type_echo_reply?
|
39
|
-
@type == TYPE_ICMP_ECHO_REPLY
|
40
|
-
end
|
41
|
-
|
42
|
-
# @return [Boolean]
|
43
|
-
def is_type_destination_unreachable?
|
44
|
-
@type == TYPE_ICMP_DESTINATION_UNREACHABLE
|
45
|
-
end
|
46
|
-
|
47
|
-
# Whether the argument ICMP is a reply of this ICMP
|
48
|
-
#
|
49
|
-
# @param [ICMP]
|
50
|
-
# @return [Boolean]
|
51
|
-
def successful_reply?(icmp)
|
52
|
-
icmp.id == @id && icmp.seq_number == @seq_number && icmp.is_type_echo_reply?
|
53
|
-
end
|
54
|
-
|
55
|
-
# Return the data format for sending with the Socket::send method
|
56
|
-
#
|
57
|
-
# @return [String]
|
58
|
-
def to_trans_data
|
59
|
-
bynary_data =
|
60
|
-
@type.to_s(2).rjust(8, "0") +
|
61
|
-
@code.to_s(2).rjust(8, "0") +
|
62
|
-
@checksum.to_s(2).rjust(16, "0") +
|
63
|
-
@id.to_s(2).rjust(16, "0") +
|
64
|
-
@seq_number.to_s(2).rjust(16, "0")
|
65
|
-
|
66
|
-
data_byte_arr = bynary_data.scan(/.{1,8}/)
|
67
|
-
data_byte_arr.map! { |byte| byte.to_i(2).chr }
|
68
|
-
data_byte_arr.join + @data
|
69
|
-
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
# Calculate carry in 16bit
|
74
|
-
# memo: https://qiita.com/kure/items/fa7e665c2259375d9a81
|
75
|
-
#
|
76
|
-
# @param num [String] ex: "11001100110100011"
|
77
|
-
# @return [Integer]
|
78
|
-
def carry_up(num)
|
79
|
-
carry_up_num = num.length - 16
|
80
|
-
original_value = num[carry_up_num, 16]
|
81
|
-
carry_up_value = num[0, carry_up_num]
|
82
|
-
sum = original_value.to_i(2) + carry_up_value&.to_i(2)
|
83
|
-
sum ^ 0xffff
|
84
|
-
end
|
85
|
-
|
86
|
-
# return checksum value
|
87
|
-
# Calculate 1's complement sum for each 16 bits
|
88
|
-
# memo: https://qiita.com/kure/items/fa7e665c2259375d9a81
|
89
|
-
#
|
90
|
-
# @return [Integer]
|
91
|
-
def checksum
|
92
|
-
# Divide into 16 bits
|
93
|
-
# ex: ["pi", "ng"]
|
94
|
-
data_arr = @data.scan(/.{1,2}/)
|
95
|
-
# Calculate each ASCII code
|
96
|
-
# ex: [28777, 28263]
|
97
|
-
data_arr_int = data_arr.map do |data|
|
98
|
-
(data.bytes[0] << 8) + (data.bytes[1].nil? ? 0 : data.bytes[1])
|
99
|
-
end
|
100
|
-
data_sum = data_arr_int.sum
|
101
|
-
|
102
|
-
sum_with_16bit = (@type << 8 + @code) + @id + @seq_number + data_sum
|
103
|
-
|
104
|
-
# calculate carry
|
105
|
-
carry_up(sum_with_16bit.to_s(2).rjust(16, "0"))
|
106
|
-
end
|
107
|
-
|
108
|
-
# generate data
|
109
|
-
#
|
110
|
-
# TODO: random
|
111
|
-
# @return [String]
|
112
|
-
def gen_data
|
113
|
-
"abcd"
|
114
|
-
end
|
115
|
-
|
116
|
-
# generate ID
|
117
|
-
#
|
118
|
-
# TODO: random
|
119
|
-
# @return [Integer]
|
120
|
-
def gen_id
|
121
|
-
0x01
|
122
|
-
end
|
123
|
-
|
124
|
-
# generate sequence number
|
125
|
-
#
|
126
|
-
# TODO: random
|
127
|
-
# @return [Integer]
|
128
|
-
def gen_seq_number
|
129
|
-
0x00af
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
data/recv_message.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
module SimplePing
|
2
|
-
# Class that stores the received message
|
3
|
-
# Implements a method to retrieve the ICMP header
|
4
|
-
class RecvMessage
|
5
|
-
# Code
|
6
|
-
#
|
7
|
-
# @return [Integer]
|
8
|
-
def code
|
9
|
-
@mesg[21].bytes[0]
|
10
|
-
end
|
11
|
-
|
12
|
-
# ID
|
13
|
-
#
|
14
|
-
# @return [Integer]
|
15
|
-
def id
|
16
|
-
(@mesg[24].bytes[0] << 8) + @mesg[25].bytes[0]
|
17
|
-
end
|
18
|
-
|
19
|
-
# constructor
|
20
|
-
#
|
21
|
-
# @param [String] mesg
|
22
|
-
def initialize(mesg)
|
23
|
-
@mesg = mesg
|
24
|
-
end
|
25
|
-
|
26
|
-
# Data
|
27
|
-
#
|
28
|
-
# @return [String]
|
29
|
-
def data
|
30
|
-
@mesg[28, @mesg.length.to_i - 28]
|
31
|
-
end
|
32
|
-
|
33
|
-
# sequence numebr
|
34
|
-
#
|
35
|
-
# @return [Integer]
|
36
|
-
def seq_number
|
37
|
-
(@mesg[26].bytes[0] << 8) + @mesg[27].bytes[0]
|
38
|
-
end
|
39
|
-
|
40
|
-
# create icmp object
|
41
|
-
#
|
42
|
-
# @return [SimplePing::ICMP]
|
43
|
-
def to_icmp
|
44
|
-
icmp = ICMP.new(code: code, type: type)
|
45
|
-
if icmp.is_type_echo?
|
46
|
-
icmp.id = id
|
47
|
-
icmp.seq_number = seq_number
|
48
|
-
icmp.data = data
|
49
|
-
end
|
50
|
-
icmp
|
51
|
-
end
|
52
|
-
|
53
|
-
# Type
|
54
|
-
#
|
55
|
-
# @return [Integer]
|
56
|
-
def type
|
57
|
-
@mesg[20].bytes[0]
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|