2
1

More than 3 years have passed since last update.

【Ruby】シンプルなPingクライアントを作ってみた

Last updated at Posted at 2020-07-26

概要

ICMP Echo Requestの送信・受信を1回だけ実行するシンプルなクライアントを作ってみたので、忘れないうちに実装時に学習したことや、気をつけたこと等をつらつらとメモ。

成果物リンク

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

目的

  • ネットワークプログラミングの練習
  • gem パッケージ公開の練習
  • 気晴らし

どんなものか/使い方

できること

  • ping(ICMP)した結果の成否をtrue/falseで返却する
  • 宛先の指定はIPアドレス

できないこと

  • FQDNでの宛先指定
  • リトライ
  • 送信データのカスタマイズ(ID指定やデータ部の指定等)
  • 等など

使い方サンプル

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権限が必須

console
> sudo ruby ping.rb
Success!

実装メモ

  • ソケットプログラミングを行うこととなるが、 ドキュメントを見るといくつかソケットにも種類があるが、今回はICMPヘッダを直に触るので、 SOCK_RAW (Rawソケット)を用いる。
    • 第一引数には Socket::AF_INET を指定する。IPヘッダ以上のヘッダを触ることができる。
  • 最終的にデータを送信(send)するときはデータを文字列で指定する必要がある。用意したICMPヘッダのデータ列を1ByteずつASCIIコードに従って文字列に変換する必要がある。
    • 例えば、「識別子」が65であれば、ASCIIコード上では65は A になるので A を送信する必要がある。
    • Ruby 上では 65.chr 等とするとASCIIコードにしたがって文字を取得できる。参考
    • ただしエンコーディングの種別は設定によって変わるらしいので注意する
  • 受信する際は recvfromメソッドによって受信し、データは文字列で取得できる
    • 取得したデータはIPヘッダも含んだ形でのデータとなっている。
    • IPヘッダのサイズは基本的に20Byteなので(違う場合もあるようだが今回は実装上は想定していない)ICMPヘッダのデータは21Byte目から順番に取得できる
    • 例えばICMPヘッダ先頭の「タイプ」であれば以下のように取得できる
      • bytes メソッドで文字列をASCIIコードに変換できる
mesg, _ = socket.recvfrom(1500)
mesg[21].bytes[0] #=> 0
  • 受信時には受信したパケットが送信した物の帰りのパケットかを判定する必要があるが、「ID」と「シーケンス番号」と「タイプ」を照合して、送信・受信の対応を確認する(以下RFCの通り)

受信したエコーメッセージに含まれるデータは、エコーリプライメッセージのデータとして返されなければならない。
識別子とシーケンス番号は、エコー送信者がエコー要求とそのリプライとを対応させるのに使用される。例えば TCP や UDP がセッションを特定するために使用するポート番号のように識別子を使用してもよいし、エコー要求のたびにシーケンス番号を増加させてもよい。エコーを返す側は、エコーリプライの中で同じ値を返す。
http://srgia.com/docs/rfc792j.html

参考

RubyでいろいろなSocket作って遊んでみた。 - Qiita https://qiita.com/MikuriyaHiroshi/items/b0a40f5e7b7be1ef327c

【Ruby】RawSocketを使ったネットワークプログラム – Euniclus https://euniclus.com/article/ruby-port-scan/

BasicSocket#send (Ruby 2.7.0 リファレンスマニュアル) 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

ASCII コードと文字を変換する (ord, chr, bytes, unpack, codepoints) | まくまくRubyノート https://maku77.github.io/ruby/number/ascii-char.html

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

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1