def self.read_interfaces
ksize = Libc.getkerninfo(KINFO_RT_IFLIST, nil, nil, 0)
log.debug('getkerninfo call was unsuccessful') if ksize.zero?
ksize_ptr = ::FFI::MemoryPointer.new(:int, ksize.size)
ksize_ptr.write_int(ksize)
result_ptr = ::FFI::MemoryPointer.new(:char, ksize)
res = Libc.getkerninfo(KINFO_RT_IFLIST, result_ptr, ksize_ptr, 0)
log.debug('getkerninfo call was unsuccessful') if res == -1
cursor = 0
interfaces = {}
while cursor < ksize_ptr.read_int
hdr = FFI::IfMsghdr.new(result_ptr + cursor)
case hdr[:ifm_type]
when FFI::RTM_IFINFO
link_addr = FFI::SockaddrDl.new(hdr.to_ptr + hdr.size)
interface_name = link_addr[:sdl_data].to_s[0, link_addr[:sdl_nlen]]
interfaces[interface_name] ||= {}
when FFI::RTM_NEWADDR
addresses = {}
addr_cursor = cursor + hdr.size
FFI::RTAX_LIST.each do |key|
xand = hdr[:ifm_addrs] & FFI::RTA_LIST[key]
next unless xand != 0
sockaddr = FFI::Sockaddr.new(result_ptr + addr_cursor)
addresses[key] = sockaddr
roundup_nr = roundup(sockaddr)
addr_cursor += roundup_nr
end
family = FFI::AF_UNSPEC
addresses.each_value do |addr|
if family != FFI::AF_UNSPEC &&
addr[:sa_family] != FFI::AF_UNSPEC &&
family != addr[:sa_family]
family = FFI::AF_MAX
break
end
family = addr[:sa_family]
end
if addresses[FFI::RTAX_NETMASK][:sa_len]
addresses[FFI::RTAX_NETMASK][:sa_family] = family
netmask = address_to_string(addresses[FFI::RTAX_NETMASK])
end
address = address_to_string(addresses[FFI::RTAX_IFA]) if addresses[FFI::RTAX_IFA][:sa_len]
if addresses[FFI::RTAX_NETMASK][:sa_len] && addresses[FFI::RTAX_IFA][:sa_len]
network = address_to_string(addresses[FFI::RTAX_IFA], addresses[FFI::RTAX_NETMASK])
end
bindings = family == FFI::AF_INET ? :bindings : :bindings6
interfaces[interface_name][bindings] ||= []
interfaces[interface_name][bindings] << {
netmask: netmask.read_string,
address: address.read_string,
network: network.read_string
}
else
log.debug("got an unknown RT_IFLIST message: #{hdr[:ifm_type]}")
end
cursor += hdr[:ifm_msglen]
end
interfaces
end