Upgrade to Pro — share decks privately, control downloads, hide ads and more …

時うどん〜Socket.getifaddrsで学ぶネットワーク編 / Tokiudon: Th...

時うどん〜Socket.getifaddrsで学ぶネットワーク編 / Tokiudon: The Socket.getifaddrs Edition

名古屋Ruby会議05

More Decks by Misaki Shioi(塩井美咲/しおい)

Other Decks in Technology

Transcript

  1. pp self 盆暗亭しおい a.k.a. 塩井美咲 @shioimm (GitHub) @coe401̲ (Former Twitter)

    @coe401.bsky.social (Bluesky) ネットワークの勉強をしています
  2. こんな配列が返ってまいりました => [#<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST LINK[lo0]>, 清八 #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST

    127.0.0.1 netmask=255.0.0.0>, #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST LINK[en0 02:00:00:00:00:01]>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST 192.0.2.16 netmask=255.255.255.0 broadcast=192.0.2.255>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST fe80::1234:5678:9abc:def0%en0 netmask=ffff:ffff:ffff:ffff::>, #<Socket::Ifaddr utun0 UP,POINTOPOINT,RUNNING,MULTICAST fe80::abcd:ef12:3456:7890%utun0 netmask=ffff:ffff:ffff:ffff::>, #<Socket::Ifaddr gif0 POINTOPOINT,MULTICAST LINK[gif0]>, #<Socket::Ifaddr stf0 0 LINK[stf0]>]
  3. 清八 うどん屋、このMacBookの ネットワークインターフェースの数はなんぼや => [#<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST LINK[lo0]>, #<Socket::Ifaddr lo0

    UP,LOOPBACK,RUNNING,MULTICAST 127.0.0.1 netmask=255.0.0.0>, #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST LINK[en0 02:00:00:00:00:01]>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST 192.0.2.16 netmask=255.255.255.0 broadcast=192.0.2.255>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST fe80::1234:5678:9abc:def0%en0 netmask=ffff:ffff:ffff:ffff::>, #<Socket::Ifaddr utun0 UP,POINTOPOINT,RUNNING,MULTICAST fe80::abcd:ef12:3456:7890%utun0 netmask=ffff:ffff:ffff:ffff::>, #<Socket::Ifaddr gif0 POINTOPOINT,MULTICAST LINK[gif0]>, #<Socket::Ifaddr stf0 0 LINK[stf0]>]
  4. この配列の要素を数えたらええんですか? 清八 うどん屋 => [#<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST LINK[lo0]>, #<Socket::Ifaddr lo0

    UP,LOOPBACK,RUNNING,MULTICAST 127.0.0.1 netmask=255.0.0.0>, #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST LINK[en0 02:00:00:00:00:01]>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST 192.0.2.16 netmask=255.255.255.0 broadcast=192.0.2.255>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST fe80::1234:5678:9abc:def0%en0 netmask=ffff:ffff:ffff:ffff::>, #<Socket::Ifaddr utun0 UP,POINTOPOINT,RUNNING,MULTICAST fe80::abcd:ef12:3456:7890%utun0 netmask=ffff:ffff:ffff:ffff::>, #<Socket::Ifaddr gif0 POINTOPOINT,MULTICAST LINK[gif0]>, #<Socket::Ifaddr stf0 0 LINK[stf0]>]
  5. うどん屋が配列にsizeメソッドを呼ぶと >> Socket.getifaddrs.size 清八 うどん屋 => [#<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST LINK[lo0]>,

    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST 127.0.0.1 netmask=255.0.0.0>, #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST LINK[en0 02:00:00:00:00:01]>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST 192.0.2.16 netmask=255.255.255.0 broadcast=192.0.2.255>, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST fe80::1234:5678:9abc:def0%en0 netmask=ffff:ffff:ffff:ffff::>, #<Socket::Ifaddr utun0 UP,POINTOPOINT,RUNNING,MULTICAST fe80::abcd:ef12:3456:7890%utun0 netmask=ffff:ffff:ffff:ffff::>, #<Socket::Ifaddr gif0 POINTOPOINT,MULTICAST LINK[gif0]>, #<Socket::Ifaddr stf0 0 LINK[stf0]>]
  6. Socket.getifaddrs Socket.getifaddrs 清八 コンピュータ >> Socket.getifaddrs => [#<Socket::Ifaddr ...>, #<Socket::Ifaddr

    ...>, #<Socket::Ifaddr ...>, #<Socket::Ifaddr ...>, #<Socket::Ifaddr ...>] Socket.getifaddrsを実行すると、 ネットワークインターフェースの情報を表す Socket::Ifaddrオブジェクトの配列が返る
  7. macOSでよく見かけるネットワークインターフェース名たち "lo*" = ループバックインターフェース >> Socket.getifaddrs.map(&:name) => ["lo0", "en0", "utun0",

    "gif0", "stf0"] その端末の内部で通信をするための仮想的なインターフェース ループバックインターフェース宛に送信されたパケットは 自身のOSによって処理され、ほかの端末との通信には利用できない
  8. macOSでよく見かけるネットワークインターフェース名たち "utun*" = VPNなどで使用される仮想的なインターフェース >> Socket.getifaddrs.map(&:name) => ["lo0", "en0", "utun0",

    "gif0", "stf0"] VPNを経由するパケットはこのインターフェースを通過した後、 VPNソフトウェアによって暗号化・カプセル化され、 実際のネットワーク経路からVPNサーバへ送信される
  9. macOSでよく見かけるネットワークインターフェース名たち "gif*" / "stf*" = トンネル通信のための仮想的なインターフェース >> Socket.getifaddrs.map(&:name) => ["lo0",

    "en0", "utun0", "gif0", "stf0"] IPパケットを別のIPパケットでカプセル化して送信する "stf*"は古いIPv6移行技術 (6to4) のためのもの
  10. アドレスとSocket::Ifaddr#addr それぞれのネットワークインターフェースには、 通信をするためのアドレス (※) が設定されることがある >> Socket.getifaddrs.first.addr => #<Addrinfo: fe80::1234:5678:9abc:def0>

    コンピュータ >> Socket.getifaddrs.last.addr => #<Addrinfo: LINK[lo0]> (※) IPアドレスやリンク層アドレス Socket::Ifaddr#addrは当該インターフェースに設定された アドレスをAddrinfoオブジェクトとして返す
  11. ➡︎ ネットマスク 「IPアドレス全体のうち、どこまでがネットワーク部か」を示す情報 IPアドレスと組み合わせることで、 そのアドレスがどのネットワークに属しているかを判断できる 例: IPアドレス 192.168.1.10 ネットマスク 255.255.255.0

    (先頭24ビットがネットワーク部) アドレス全体 192 . 168 . 1 10 ネットマスク 255 . 255 . 255 10 ネットワーク部 ホスト部 192.168.1.0 から 192.168.1.255までのアドレスを含むネットワークに属し ホスト部が10であるアドレス
  12. インターフェースフラグ インターフェースフラグには以下のような情報が含まれる ・稼働状態 (稼働中 / 稼働していない) ・対応する通信方式 (BROADCAST/MULTICAST/POINTOPOINT/LOOPBACK) ・パケット処理の挙動 etc...

    (OSによっても異なる) Socket::Ifaddr#inspectの方が人間の目にはやさしいかも... >> ifaddr = Socket.getifaddrs.sample => #<Socket::Ifaddr lo0 ... 127.0.0.1 ...> >> ifaddr.flags # => 32841 >> ifaddr.flags & Socket::IFF_UP != 0 # => true >> ifaddr.inspect => "#<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST 127.0.0.1 ...>" インターフェースフラグ
  13. 自分自身を表すアドレス ループバックアドレスは その端末の内部で通信をするためのアドレス IPv4アドレス ループバック プライベート リンクローカル IPv6アドレス パブリック ループバック

    ユニークローカル グローバル リンクローカル ループバックアドレス宛に送信されたパケットは 自身のOSによって処理され、ほかの端末との通信には利用できない
  14. Addrinfo#ipv4̲loopback? / #ipv6̲loopback? Addrinfo#ipv4̲loopback? / Addrinfo#ipv6̲loopback? で IPv4またはIPv6のループバックアドレスの判定ができる >> ifaddr

    = Socket.getifaddrs.sample => #<Socket::Ifaddr lo0 ...127.0.0.1 ...> コンピュータ >> ifaddr.addr => #<Addrinfo: 127.0.0.1> >> ifaddr.addr.ipv4_loopback? => true 代表的なループバックアドレスは 127.0.0.1 (IPv4)、::1 (IPv6)
  15. インターネット上で通信するためのアドレス パブリックアドレス (IPv4) / グローバルユニキャストアドレス (IPv6) は インターネット上で通信するためのアドレス IPv4アドレス ループバック

    プライベート IPv6アドレス パブリック ループバック ユニークローカル リンクローカル これらはグローバルに一意なアドレスであり、 ルータを越えて広い範囲へ通信可能 リンクローカル グローバル
  16. パブリックアドレス/ グローバルユニキャストアドレスの判定 パブリックアドレス / グローバルユニキャストアドレスを判定する APIは、今のところAddrinfoクラスには存在しない >> ifaddr = Socket.getifaddrs.sample

    => #<Socket::Ifaddr en0 ...203.0.113.10 ...> コンピュータ >> addr = ifaddr.addr => #<Addrinfo: 203.0.113.10> >> require "ipaddr" >> ip = IPAddr.new(addr.ip_address) >> addr.ipv4? && !addr.ipv4_loopback? && !addr.ipv4_private? && !addr.ipv4_multicast? && !ip.link_local? => true 判定するために 自前のロジックが必要
  17. 限られた範囲のネットワーク内で通信するためのアドレス (IPv4) プライベートアドレス (IPv4) は 限られた範囲のネットワーク内での通信に使用するアドレス IPv4アドレス ループバック プライベート リンクローカル

    IPv6アドレス パブリック ループバック ユニークローカル グローバル リンクローカル 限られた範囲のネットワーク … 家庭内・企業内ネットワークなど
  18. Addrinfo#ipv4̲private? Addrinfo#ipv4̲private?で プライベートIPv4アドレスの判定ができる >> ifaddr = Socket.getifaddrs.sample => #<Socket::Ifaddr en0

    ... 192.168.1.1 ...> コンピュータ >> ifaddr.addr => #<Addrinfo: 192.168.1.1 > >> ifaddr.addr.ipv4_private? => true
  19. プライベートアドレス (IPv4) プライベートアドレスとして以下のアドレス範囲が予約されている 10.0.0.0/8 (10.0.0.0 〜 10.255.255.255) 172.16.0.0/12 (172.16.0.0 〜

    172.31.255.255) 192.168.0.0/16 (192.168.0.0 〜 192.168.255.255) どのネットワークも同じ範囲からアドレスを割り当てる
  20. プライベートアドレス (IPv4) プライベートアドレスとして以下のアドレス範囲が予約されている 10.0.0.0/8 (10.0.0.0 〜 10.255.255.255) 172.16.0.0/12 (172.16.0.0 〜

    172.31.255.255) 192.168.0.0/16 (192.168.0.0 〜 192.168.255.255) どのネットワークも同じ範囲からアドレスを割り当てる IPv4アドレスの利用を節約するため 32ビットで表現できるアドレスの数は約43億個。 プライベートネットワーク内のアドレスは グローバルに一意である必要がない それぞれのプライベートネットワークで共通のアドレス範囲を利用する
  21. プライベートアドレス (IPv4) プライベートアドレスとして以下のアドレス範囲が予約されている 10.0.0.0/8 (10.0.0.0 〜 10.255.255.255) 172.16.0.0/12 (172.16.0.0 〜

    172.31.255.255) 192.168.0.0/16 (192.168.0.0 〜 192.168.255.255) どのネットワークも同じ範囲からアドレスを割り当てる IPv4アドレスの利用を節約するため 32ビットで表現できるアドレスの数は約43億個。 プライベートネットワーク内のアドレスは グローバルに一意である必要がない プライベートアドレスを持つ端末がインターネット上の相手と通信したいときはどうする?
  22. 限られた範囲のネットワーク内で通信するためのアドレス (IPv6) IPv6の場合、プライベートIPv4アドレスと似た用途で ユニークローカルアドレス (ULA) が利用される IPv4アドレス ループバック プライベート IPv6アドレス

    パブリック リンクローカル ループバック ユニークローカル リンクローカル グローバルインターネットでルーティングされない点、 適切に経路が設定されていれば複数サブネット間で通信できる点が プライベートIPv4アドレスとおなじ グローバル
  23. Addrinfo#ipv6̲unique̲local? Addrinfo#ipv6̲unique̲local?でULAかどうかを判定できる >> ifaddr = Socket.getifaddrs.sample => #<Socket::Ifaddr en0 ...fd12:3456:789a:1::10

    ...> コンピュータ >> ifaddr.addr => #<Addrinfo: fd12:3456:789a:1::10> >> ifaddr.addr.ipv6_unique_local? => true
  24. ユニークローカルアドレス (ULA) (IPv6) ULAのアドレス範囲として fc00::/7 が予約されている ※ 実際にローカルで生成して利用することが定められている アドレス範囲は fd00::/8

    https://datatracker.ietf.org/doc/html/rfc4193 プレフィックス 例 fd 12:3456:789a 0001::10 GlobaI D プレフィックスに疑似ランダムに生成したGlobal ID (40ビット) を含む プライベートIPv4アドレスは、 ↔︎ どのネットワークでも共通の範囲からアドレスを割り当てる
  25. ユニークローカルアドレス (ULA) (IPv6) ULAのアドレス範囲として fc00::/7 が予約されている ※ 実際にローカルで生成して利用することが定められている アドレス範囲は fd00::/8

    https://datatracker.ietf.org/doc/html/rfc4193 プレフィックス 例 fd 12:3456:789a 0001::10 GlobaI D プレフィックスに疑似ランダムに生成したGlobal ID (40ビット) を含む IPv6のアドレス空間が十分に大きいため IPv4の32ビットに対してIPv6は128ビット
  26. ユニークローカルアドレス (ULA) (IPv6) ULAのアドレス範囲として fc00::/7 が予約されている ※ 実際にローカルで生成して利用することが定められている アドレス範囲は fd00::/8

    https://datatracker.ietf.org/doc/html/rfc4193 プレフィックス 例 fd 12:3456:789a 0001::10 GlobaI D プレフィックスに疑似ランダムに生成したGlobal ID (40ビット) を含む 異なるネットワークでそれぞれにプレフィックスを生成しても衝突しにくい 異なるネットワーク同士をVPNなどで接続するときにも便利
  27. リンクローカルアドレス リンク = ルータを経由せずに直接通信できる範囲 同一リンク 同一リンク fe80::30宛 fe80::10 ルータ fe80::30

    fe80::20 fe80::20宛 同じ有線LANやWi-Fiネットワークに 接続されている機器同士が一つのリンクに属する
  28. Addrinfo#ipv6̲linklocal? IPv6ではAddrinfo#ipv6̲linklocal?で リンクローカルアドレスかどうかを判定できる >> ifaddr = Socket.getifaddrs.sample => #<Socket::Ifaddr en0

    ...fe12:3456:789a:1::10 ...> コンピュータ >> ifaddr.addr => #<Addrinfo: fe12:3456:789a:1::10> >> ifaddr.addr.ipv6_linklocal? => true
  29. IPv4のリンクローカルアドレスの判定 一方、IPv4のリンクローカルアドレスを判定するAPIは 今のところAddrinfoクラスには存在しない >> ifaddr = Socket.getifaddrs.sample => #<Socket::Ifaddr en0

    ...169.254.1.1 ...> コンピュータ >> ifaddr.addr => #<Addrinfo: 169.254.1.1> >> ifaddr.addr.ipv4_linklocal? => NoMethodError >> require "ipaddr" >> ip = IPAddr.new(addr.ip_address) >> !ip.link_local? => true ipaddrライブラリで 判定できる
  30. リンクローカルアドレス (IPv6) IPv6のリンクローカルアドレスには アドレス範囲として fe80::/10 が予約されている 例 fe80::1234 %en0 アドレス

    ゾーンID ゾーンID ... リンクを識別するためのID 一つの端末が複数のリンクに接続している場合、 異なるリンク上に同じアドレスが重複して設定される可能性がある。 端末は通信時にゾーンIDを用いて利用するリンクを識別する
  31. IPv6の場合 IPv6では一つのネットワークインターフェースに対し 役割の異なる複数のアドレスが共存することが想定されている ルータ en0 インターネット fe80::aede:48 :fe00:1122%en0 リンクローカルアドレス fd12:3456:789a:1::20

    ユニークローカルアドレス 2001:db8:1234:1::20 グローバルユニキャストアドレス リンクローカルアドレス設定済みのインターフェースに対し、 ff 必要に応じてグローバルユニキャストアドレス/ULAを設定できる
  32. IPv6の場合 同じインターフェースに複数のアドレスが設定されている場合、 通常はOSが宛先に応じて適切な送信元アドレスを選択する ※ アプリケーションが送信元アドレスを指定しない場合 2001:db8:5678:1::10 ルータ en0 インターネット fe80::aede:48

    :fe00:1122%en0 リンクローカルアドレス fd12:3456:789a:1::20 ユニークローカルアドレス 2001:db8:1234:1::20 グローバルユニキャストアドレス 例 OSが選択 宛先がリンクローカルの場合はリンクローカルアドレス、 ff インターネットの場合はグローバルユニキャストアドレス
  33. IPv6の場合 Q. ULAが設定されている端末から インターネットに接続したい場合はどうする? ルータ en0 インターネット fe80::aede:48 :fe00:1122%en0 リンクローカルアドレス

    fd12:3456:789a:1::20 ユニークローカルアドレス 2001:db8:1234:1::20 グローバルユニキャストアドレス ff A. (一般的には) グローバルユニキャストアドレスで通信する
  34. 同じネットワークインターフェース上のIPv4アドレス IPv4/IPv6を両方利用する端末の場合 (デュアルスタック)、 同じインターフェースにIPv6 / IPv4アドレスを同時に設定できる ルータ en0 インターネット fe80::aede:48

    :fe00:1122%en0 リンクローカルアドレス fd12:3456:789a:1::20 ユニークローカルアドレス 2001:db8:1234:1::20 グローバルユニキャストアドレス ff 203.0.113.10 パブリックIPv4アドレス
  35. 同じネットワークインターフェース上のリンク層アドレス ネットワークインターフェースには IPアドレス以外にリンク層アドレスが設定されることもある ※ リンク層アドレス…同じリンク上でリンク層の通信相手を識別するアドレス ルータ en0 インターネット ネットワーク層 fe80::aede:48

    :fe00:1122%en0 リンクローカルアドレス fd12:3456:789a:1::20 ユニークローカルアドレス 2001:db8:1234:1::20 グローバルユニキャストアドレス 203.0.113.10 パブリックIPv4アドレス リンク層 ff ff fe80::aede:48 :fe00:1122%en0 リンク層アドレス
  36. Socket.getifaddrsの返り値の正体 Socket.getifaddrsの実行結果(例) Socket.getifaddrs => [..., en0という名前のネットワークインターフェース #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST 192.0.2.16

    netmask=255.255.255.0 broadcast=192.0.2.255 >, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST fe80::1234:5678:9abc:def0%en0 netmask=ffff:ffff:ffff:ffff:: >, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST LINK[en0 02:00:00:00:00:01] >, ...] 例 "en0"という名前のネットワークインターフェースに
  37. Socket.getifaddrsの返り値の正体 Socket.getifaddrsの実行結果(例) Socket.getifaddrs => [..., #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST 192.0.2.16 netmask=255.255.255.0

    broadcast=192.0.2.255 >, IPv4アドレス #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST fe80::1234:5678:9abc:def0%en0 netmask=ffff:ffff:ffff:ffff:: >, IPv6アドレス #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST LINK[en0 02:00:00:00:00:01] >, リンク層アドレス ...] 例 IPv4アドレス、IPv6アドレス、リンク層アドレスが それぞれ設定されている
  38. Socket.getifaddrsの返り値の正体 Socket.getifaddrsの実行結果(例) Socket.getifaddrs => [..., #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST 192.0.2.16 netmask=255.255.255.0

    broadcast=192.0.2.255 >, ネットマスク #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST fe80::1234:5678:9abc:def0%en0 netmask=ffff:ffff:ffff:ffff:: >, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST LINK[en0 02:00:00:00:00:01] >, ...] 例 それぞれのIPアドレスのネットマスクを確認できる
  39. Socket.getifaddrsの返り値の正体 Socket.getifaddrsの実行結果(例) Socket.getifaddrs => [..., インターフェースフラグ #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST 192.0.2.16

    netmask=255.255.255.0 broadcast=192.0.2.255 >, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST fe80::1234:5678:9abc:def0%en0 netmask=ffff:ffff:ffff:ffff:: >, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST LINK[en0 02:00:00:00:00:01] >, ...] 例 インターフェース自体は同じなので、 インターフェースフラグは共通
  40. Socket.getifaddrsの返り値の正体 Socket.getifaddrsの実行結果(例) Socket.getifaddrs => [..., #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST 192.0.2.16 netmask=255.255.255.0

    broadcast=192.0.2.255 >, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST fe80::1234:5678:9abc:def0%en0 netmask=ffff:ffff:ffff:ffff:: >, #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST LINK[en0 02:00:00:00:00:01] >, ...] Socket.getifaddrsはインターフェースごとではなく、 インターフェースに関連づけられたアドレス情報ごとに Socket::Ifaddrオブジェクトを返す
  41. Socket.getifaddrsの返り値の正体 Socket.getifaddrsの実行結果(例) Socket.getifaddrs => [#<Socket::Ifaddr lo0 UP,LOOPBACK, ... LINK[lo0]>, #<Socket::Ifaddr

    lo0 UP,LOOPBACK, ... 127.0.0.1 ...>, lo0 #<Socket::Ifaddr lo0 UP,LOOPBACK, ... ::1 ...>, #<Socket::Ifaddr en0 UP,BROADCAST, ..., LINK[en0 02:00:00:00:00:01]>, #<Socket::Ifaddr en0 UP,BROADCAST, ... 192.0.2.16 ...>, en0 #<Socket::Ifaddr en0 UP,BROADCAST, ... fe80::1234:5678:9abc:def0%en0 ...>, #<Socket::Ifaddr utun0 UP,POINTOPOINT, ... fe80::abcd:ef12:3456:7890%utun0 ...>, #<Socket::Ifaddr gif0 POINTOPOINT, ... LINK[gif0]>, #<Socket::Ifaddr stf0 0 LINK[stf0]>] gif0 utun0 stf0 同じネットワークインターフェース名を持つ複数のSocket::Ifaddrオブジェクトを含む
  42. うどん屋!! このMacBookの ネットワークインターフェースの数はなんぼや!! 喜六 => ["lo0", "en0", "utun0", "gif0", "stf0"]

    はい、五つで うどん屋 …六つ、七つ、八つ…??? 喜六 …で三文損する、というお話