IOCTL呼び出しのバッファへのポインタ
概要
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 ifconfig」の署名 (SIOCGIFCONF で使用) はバッファーに渡す必要がありました。
署名は次のとおりです。
struct ifconf {
int ifc_len;
char __user *ifcu_buf;
};
Ruby から 4096 バイトのバッファを使用して SIOCGIFCONF ioctl コマンドを呼び出すにはどうすればよいですか?
解決策
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 呼び出しに渡す 2 番目のバッファを作成します。バッファは 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")
フォーマット指定子は次のように分類されます。
これで、電話をかけることができます。
SIOCGIFCONF = 0x8912
sock.ioctl(SIOCGIFCONF, ifconf)
SIOCGIFCONF 呼び出しは ifconf バッファを変更し、ifc_len を更新します。 ifreqs バッファに実際に格納されているデータのバイト数。私たちは 配列のその要素だけを解凍すると、それがわかります。
data_size = ifconf.unpack('l!').first
p data_size # => 120
ifreqs に保存されたデータのデコードは、演習として残されています。 読者。