ruby 指向IOCTL调用中的缓冲区的指针

jdzmm42g  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(87)

我正在使用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中使用4096字节的缓冲区调用SIOCGIFCONF ioctl命令?

txu3uszq

txu3uszq1#

使用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

How this works

创建缓冲区,ioctl将在其中存储接口信息数组:

ifreqs = ' ' * 4096

现在创建第二个缓冲区以传递给ioctl调用。缓冲区将是一个表示ifconf struct的字符串:

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")

格式说明符分为:

  • “l!”-平台原生大小的带符号长。这将编码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 中的数据解码留给读者练习。

相关问题