[Ruby] [Ruby] I made a simple Ping client

2 minute read

Overview

I tried to make a simple client that sends and receives ICMP Echo Request only once, so before I forget it, I memorized what I learned during implementation and what I was careful about.

https://rubygems.org/gems/simple_ping https://github.com/kuredev/simple_ping

Purpose

  • Network programming practice
  • Practice of publishing gem package
  • Distraction

What it is/how to use

What you can do

  • Return the success or failure of the ping (ICMP) result with true/false
  • Destination is IP address

Things impossible

  • Addressing by FQDN
  • Retry
  • Customized transmission data (ID specification, data section specification, etc.)
  • Etc., etc

Usage sample

ping.rb


require "simple_ping"

ping_client = SimplePing::Client.new(src_ip_addr: "192.168.1.100")
puts ping_client.exec(dest_ip_addr: "192.168.1.101")? "Success!" :"Failed.."

*Root privileges are required for execution

console


> sudo ruby ping.rb
Success!

Implementation notes

  • Socket programming will be done, but if you look at docs,youcanfindsomesocketsTherearealsodifferenttypes,butthistimeIwilltouchtheICMPheaderdirectly,souseSOCK_RAW(Rawsocket).
  • When sending data (send), it is necessary to specify the data as a character string. There is. It is necessary to convert the data string of the prepared ICMP header into a character string according to the ASCII code 1 byte at a time. -For example, if the “identifier” is 65, 65 becomes A in ASCII code, so A You need to send a . -On Ruby, you can get characters according to ASCII code by setting 65.chr` etc. Reference -However, note that the encoding type seems to vary depending on the setting (https://docs.ruby-lang.org/ja/latest/method/Integer/i/chr.html)
  • When receiving, it is received by recvfrom method, and the data can be obtained as a character string. -The acquired data is data including the IP header. -The size of the IP header is basically 20 bytes (it may be different, but this time it is not assumed in the implementation) ICMP header data can be acquired sequentially from the 21st byte -For example, if the “type” at the beginning of the ICMP header can be obtained as follows -Convert string to ASCII code by bytes method
mesg, _ = socket.recvfrom(1500)
mesg[21].bytes[0] #=> 0
  • When receiving, it is necessary to judge whether the received packet is a return packet of the sent one, but check the correspondence between sending and receiving by checking the “ID”, “sequence number” and “type”. (According to RFC)

The data contained in the received echo message shall be returned as the data of the echo reply message. The identifier and sequence number are used by the echo sender to associate the echo request with its reply. The identifier may be used, such as the port number used by TCP or UDP to identify the session, or the sequence number may be incremented with each echo request. The echo return side returns the same value in the echo reply. http://srgia.com/docs/rfc792j.html

Reference

I made various Sockets with Ruby and played with them. -Qiita https://qiita.com/MikuriyaHiroshi/items/b0a40f5e7b7be1ef327c

[Ruby] Network program using RawSocket – Euniclus https://euniclus.com/article/ruby-port-scan/

BasicSocket#send (Ruby 2.7.0 Reference Manual) https://docs.ruby-lang.org/ja/latest/method/BasicSocket/i/send.html

Internet Control Message Protocol-Wikipedia https://ja.wikipedia.org/wiki/Internet_Control_Message_Protocol#ICMP%E3%83%98%E3%83%83%E3%83%80

Convert ASCII code and characters (ord, chr, bytes, unpack, codepoints) Makukuma Ruby Note https://maku77.github.io/ruby/number/ascii-char.html

RFC792(INTERNET CONTROL MESASAGE PROTOCOL) http://srgia.com/docs/rfc792j.html