LoginSignup
63
61

More than 5 years have passed since last update.

Ruby 2.1.0 では Socket.getifaddrs で簡単にインターフェイスのアドレスを取れる

Last updated at Posted at 2013-12-29

Ruby 2.1.0 に Socket.getifaddrs が登場

ネットワーク畑の人間からすれば、 Ruby 2.1.0 の目玉機能は間違いなく Socket.getifaddrs だ。これがあれば、「インターフェイス名からそのインターフェイスの持っているIPアドレスを確認する」ことが簡単にできるようになる。

これまで

これまでは、 ifconfig や ip コマンドの結果から頑張って取ってこなくてはならなかった。

res = `ifconfig eth0`
res =~ /inet addr:(\d+\.\d+\.\d+\.\d+)/
addr = $1

できるけど気持ち悪いし、v6アドレスになると死ぬし、外部コマンド実行をするとエラー対応とかセキュリティとかが厄介な問題になる。

これから

Ruby 2.1.0 からは、 Socket.getifaddrs メソッドが追加されている。これからは、Ruby に完結したコードでアドレスが取れるようになる。

拡張ライブラリ socket に Socket.getifaddrs というメソッドを新設しています。 これは getifaddrs(3) のラッパで、Socket::Ifaddr というネットワークインタフェースの情報を保持するクラスを追加してその配列を返すようにしています。これによりローカルアドレスとそのネットワークインタフェースの対応やネットマスク、Macアドレスの対応などがわかるようになります。 ifconfig の結果を parse してゴニョゴニョやってたりしたのが簡単にできるようになるんじゃないかと思います。
http://d.hatena.ne.jp/nagachika/20130511/ruby_trunk_changes_40634_40646

ということで、あ、やっぱり ifconfig ゴニョゴニョするの楽にしたいって話はあったんだ。すごく…嬉しいです…。

使い方

単純に出力を見てみる

require 'socket'
Socket.getifaddrs
#=> [#<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 PACKET[protocol=0 lo hatype=772 HOST hwaddr=00:00:00:00:00:00]>,
     #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=00:0c:29:XX:XX:XX] broadcast=PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=ff:ff:ff:ff:ff:ff]>,
     #<Socket::Ifaddr tun0 UP,POINTOPOINT,RUNNING,NOARP,MULTICAST,0x10000>,
     #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 127.0.0.1 netmask=255.0.0.0>,
     #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 192.168.106.129 netmask=255.255.255.0 broadcast=192.168.106.255>,
     #<Socket::Ifaddr tun0 UP,POINTOPOINT,RUNNING,NOARP,MULTICAST,0x10000 10.111.0.2 netmask=255.255.255.255 dstaddr=10.111.0.1>,
     #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
     #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 fe80::XXXX:XXXX:XXXX:XXXX%eth0 netmask=ffff:ffff:ffff:ffff::>]

Socket.getifaddrs は、 Socket::Ifaddr オブジェクトの配列を返す。

インターフェイスに紐付くオブジェクトを取得する

返ってくるのが単なる Array オブジェクトなので、普通に Array#select で絞り込めばわかりやすい。

require 'socket'
Socket.getifaddrs.select{|x| x.name == "eth0"}
#=> [#<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=00:0c:29:XX:XX:XX] broadcast=PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=ff:ff:ff:ff:ff:ff]>,
     #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 192.168.106.129 netmask=255.255.255.0 broadcast=192.168.106.255>,
     #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 fe80::XXXX:XXXX:XXXX:XXXX%eth0 netmask=ffff:ffff:ffff:ffff::>]

これで、 eth0 という名前のインターフェイスに紐付くアドレス情報がすべて手に入った。

欲しいアドレスファミリを指定する

IPv4 アドレスだけがほしいなら、条件をちょっと追加してやればいい。

require 'socket'
Socket.getifaddrs.select{|x| x.name == "eth0" and x.addr.ipv4?}
#=> [#<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 192.168.106.129 netmask=255.255.255.0 broadcast=192.168.106.255>]

上の x.addrAddrinfo オブジェクトなので、ほかにもアドレスに関する各種関数が利用できる。マルチキャストか、プライベートか、といったあたりなら一発だ。

あるインターフェイスに紐付いた IPv4 アドレスを文字列として取得する

eth0 に紐付いている IPv4 アドレスの文字列が欲しい!と思ったときは、下のように書けばいいことになる。

require 'socket'
Socket.getifaddrs.select{|x|
  x.name == "eth0" and x.addr.ipv4?
}.first.addr.ip_address
#=> "192.168.106.129"

意味するところがとっても明確。
とはいえ、上の例のメソッドチェーンは長い。メソッドチェーンが長いってことは、真面目に作るならエラー処理もたくさん必要ってこと。実際にコードに利用する際は気をつけて。

まとめ

ということで、 Ruby 2.1.0 からは Socket.getifaddrs メソッドが使用できるようになった。
これまでは、アドレス情報を取ろうとしたら ifconfig からカリカリと取得しなければならなかったけれど、これからはそんなことをしなくてもよくなった。もっと構造化された枠内で、 Ruby らしいコードでアドレスを取得できる。幸せ。

akrさん、usaさんはじめ、コミッタのみなさんに感謝。
https://groups.google.com/forum/#!msg/ruby-core-google/BnOLZkp1CQk/zqqQ-F57RxgJ
http://magazine.rubyist.net/?0044-CRubyCommittersWhosWho2013

63
61
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
63
61