4

Ruby と bit-struct を使用して、テスト セットアップでネットワーク インターフェイスを構成しています。これはほとんどの IOCTL 呼び出しで正常に機能しますが、SIOCGIFCONF を呼び出す方法がわかりません。

次に例を示します。

インターフェイスの MAC アドレスを取得したい場合は、次のように記述します。

class LinuxIfreqMacAddr < BitStruct
  char       :name,    128
  unsigned   :type,     16, :endian => :native
  hex_octets :macaddr,  48
  pad        :padding,  64
end

ifr = LinuxIfreqMacAddr.new
ifr.name = "eth0"
s.ioctl(SIOCGIFHWADDR, ifr) # s is a socket
puts ifr.macaddr

これは問題なく動作し、eth0 の MAC アドレスが表示されます。しかし、"struct ifconf" (SIOCGIFCONF で使用される) の署名には、バッファを渡す必要があります。

署名は次のとおりです。

struct ifconf  {
    int     ifc_len;
    char __user *ifcu_buf;
};

Ruby から SIOCGIFCONF ioctl コマンドを 4096 バイトのバッファで呼び出すにはどうすればよいですか?

4

1 に答える 1

2

Array#packの "P" 指定子を使用して、バッファーへのポインターを格納します。

require 'socket'
sock = UDPSocket.new
ifreqs = ' ' * 4096
ifconf = [ifreqs.size, ifreqs].pack("l!P")
SIOCGIFCONF = 0x8912
sock.ioctl(SIOCGIFCONF, ifconf)
data_size = ifconf.unpack('l!').first
p data_size # => 120

これがどのように機能するか

ioctl がインターフェース情報の配列を格納するバッファーを作成します。

ifreqs = ' ' * 4096

次に、ioctl 呼び出しに渡すバッファを作成します。バッファはifconf構造体を表す文字列になります:

struct ifconf {
    int                 ifc_len; /* size of buffer */
    union {
        char           *ifc_buf; /* buffer address */
        struct ifreq   *ifc_req; /* array of structures */
    };
};

Array#packを使用してそれを行います。

ifconf = [ifreqs.size, ifreqs].pack("l!P")

フォーマット指定子は次のように分類されます。

  • 「っ!」- プラットフォームのネイティブ サイズの符号付き long。これは をエンコードしifreqs.sizeます。

  • "P" - 固定長バッファーへのポインター。これは、文字列に格納されているバッファのアドレスをエンコードしifreqsます。

これで、呼び出しを行うことができます。

SIOCGIFCONF = 0x8912
sock.ioctl(SIOCGIFCONF, ifconf)

SIOCGIFCONF 呼び出しは、ifconf バッファーを変更し、バッファーにifc_len実際に格納されているデータのバイト数に更新しますifreqs。配列のその要素だけを解凍することで、それを確認できます。

data_size = ifconf.unpack('l!').first
p data_size # => 120

ifreqsに格納されたデータのデコードは、読者の課題として残されています。

于 2015-08-10T00:35:06.017 に答える