RubyでRawソケットでイーサネットフレームを丸ごと受信するメモ。 Rawソケットを使ったプログラミングは以前ICMPは扱ったことがあったが、イーサネットフレーム全体の扱い方が分からなかった。
C言語のサンプルはたくさん出てくるけど、Rubyのサンプルや解説はなかなか出てこなかった。 どうやらソケットをバインドする時の値がポイントらしいのだが、なかなか深い部分を理解しないと難しいようで、サンプルを探していたら以下のコードを利用したら実現できた。
コードは以下の通り。
recvfrom
で取得される文字列は値をASCIIコードで変換されているようなので、パケットのヘッダとしての値を取得するように変換する必要があるみたい。
実際に socket2.rb
の中身を見るとソケットの扱い方を確認できるが、なかなか解読が大変なのでまた別途。
require_relative './socket2/lib/socket2.rb' # https://github.com/prolaag/socket2 sock = Socket.new(Socket::AF_PACKET, Socket::SOCK_RAW, Socket::ETH_P_ALL) sock.bind_if("eth1") payload, _ = sock.recvfrom(1514) # ASCII エンコードの文字列で格納される # 実際にパケットの値として確認するには各ヘッダの値を数値(16進数)で取得する必要がある # つまり、 ASCII -> 数値(String.ord) -> 16進数(Integer.to_s(16))の変換が必要 payloads = payload.chars payloads.map! { |char| char.ord } payloads.map! { |num| num.to_s(16) } pp payloads
実行結果
上記の pp
で出力した値が以下。WireSharkでパケットキャプチャした値と同一のものを取得出来ている。
["ff", "ff", "ff", "ff", "ff", "ff", "a", "b1", "a9", "1e", "67", "7a", "8", "6", "0", "1", "8", "0", "6", "4", "0", "1", "a", "b1", "a9", "1e", "67", "7a", "ac", "1f", "0", "1", "0", "0", "0", "0", "0", "0", "ac", "1f", "2", "65"]