Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@kure

【Ruby】ソケットをプロミスキャスモードにする

メモ

  • 原理的には以下ページの通りに行う。 setsockopt を呼び出して、その時に PACKET_ADD_MEMBERSHIP オプションとそのオプションに必要な struct packet_mreq のデータを渡せば良い。 Man page of PACKET
  • struct packet_mreqはCの構造体であるが、参考リンクの通り色々と調べたところ、Rubyから渡す場合は構造体のメンバのデータを順番に並べた文字列を渡せば良さそう。
  • 例えば、 mr_ifindex はインターフェース番号(int=4Byte)なので、Rubyの文字列の一文字のデータはCのchar1つに変換されるよう(動作的にそう見えるが厳密には違うかも)なので、インターフェース番号を加えた4文字の文字列を渡せば良い。下記の mr_ifindex メソッドであれば、例えば、インターフェース番号が 1 だったら "1000" が返る。
  • ETH_P_ALL はとりあえず全てのプロトコルを対象とした番号(0x0003)をネットワークバイトオーダーに変換(htons)した値を指定。
  • 実行には root 権限が必要。

サンプルコード

require "socket"

SOL_PACKET = 0x0107 # bits/socket.h
PACKET_ADD_MEMBERSHIP = 0x0001 # netpacket/packet.h
PACKET_MR_PROMISC = 0x0001 # netpacket/packet.h
ETH_P_ALL = 768 # htons(ETH_P_ALL), linux/if_ether.h

# @return [Integer]
def if_name_to_index(if_name)
  Socket.getifaddrs.find do |ifaddr|
     ifaddr.name == if_name
  end&.ifindex
end

# int(4Byte)
#
# @return [String]
def mr_ifindex(if_name)
  [[if_name_to_index(if_name)].pack("c")].pack("a4")
end

# unsigned short(2Byte)
#
# @return [String]
def mr_type
  [PACKET_MR_PROMISC].pack("S")
end

# unsigned short(2Byte)
#
# @return [String]
def mr_alen
  [0].pack("S")
end

# unsigned short(1Byte * 8)
#
# @return [String]
def mr_address
  [0].pack("C")*8
end

# https://linuxjm.osdn.jp/html/LDP_man-pages/man7/packet.7.html
# struct packet_mreq {
#  int            mr_ifindex;    /* インターフェース番号 */ 4Byte
#  unsigned short mr_type;       /* 動作 */ 2Byte
#  unsigned short mr_alen;       /* アドレスの長さ */ 2Byte
#  unsigned char  mr_address[8]; /* 物理層のアドレス */ 1Byte * 8
#};
#
# @return [String]
def mreq(interface)
  mr_ifindex(interface) + mr_type + mr_alen + mr_address
end

mreq = mreq("eth0")

sock = Socket.new(Socket::AF_PACKET, Socket::SOCK_RAW, ETH_P_ALL)
sock.setsockopt(SOL_PACKET, PACKET_ADD_MEMBERSHIP, mreq)

参考

Ruby Raw Socket on Linux (ruby 1.9.3, linux x86_64) https://gist.github.com/k-sone/8036832

0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
kure

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?