simple_ping 0.1.0 → 0.1.1
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.
- 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
|