memo.log

技術情報の雑なメモ

【Ruby】Rawソケットでイーサネットフレームをまるごと受信するメモ

RubyでRawソケットでイーサネットフレームを丸ごと受信するメモ。 Rawソケットを使ったプログラミングは以前ICMPは扱ったことがあったが、イーサネットフレーム全体の扱い方が分からなかった。

qiita.com

C言語のサンプルはたくさん出てくるけど、Rubyのサンプルや解説はなかなか出てこなかった。 どうやらソケットをバインドする時の値がポイントらしいのだが、なかなか深い部分を理解しないと難しいようで、サンプルを探していたら以下のコードを利用したら実現できた。

github.com

コードは以下の通り。 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"]

f:id:kuredev:20201115231639p:plain