gpt4 book ai didi

ruby - 使用 Ruby 和 ioctl 以编程方式获取 wifi BSSID

转载 作者:太空狗 更新时间:2023-10-29 12:33:36 29 4
gpt4 key购买 nike

使用 Getting essid via ioctl in ruby作为模板,我想获取 BSSID 而不是 ESSID。但是,不是 C 开发人员,有一些事情我不明白。

到目前为止,我所拥有的有效:( ...

注意 我有点困惑,因为我的一部分认为,根据 wireless.h 中的一些评论,BSSID 只能通过 ioctl 设置。但是,get 的 ioctl 存在。再加上我几乎完全不了解更中间的 C 类型主义(结构、联合和其他东西 ;)),我根本不知道。

def _get_bssid(interface)
# Copied from wireless.h
# supposing a 16 byte address and 32 byte buffer but I'm totally
# guessing here.
iwreq = [interface, '' * 48,0].pack('a*pI')
sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)

# from wireless.h
# SIOCGIWAP 0x8B15 /* get access point MAC addresses */
sock.ioctl('0x8B15', iwreq) # always get an error: Can't convert string to Integer

puts iwreq.inspect
end

因此,与此同时,我正在使用 wpa_cli 方法来获取 BSSID,但我更愿意使用 IOCTL:

def _wpa_status(interface)
wpa_data = nil

unless interface.nil?
# need to write a method to get the src_sock_path
# programmatically. Fortunately, for me
# this is going to be the correct sock path 99% of the time.
# Ideas to get programmatically would be:
# parse wpa_supplicant.conf
# check process table | grep wpa_suppl | parse arguments
src_sock_path = '/var/run/wpa_supplicant/' + interface
else
return nil
end

client_sock_path = '/var/run/hwinfo_wpa'

# open Domain socket
socket = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM, 0)

begin
# bind client domain socket
socket.bind(Socket.pack_sockaddr_un(client_sock_path))

# connect to server with our client socket
socket.connect(Socket.pack_sockaddr_un(src_sock_path))

# send STATUS command
socket.send('STATUS', 0)

# receive 1024 bytes (totally arbitrary value)
# split lines by \n
# store in variable wpa_data.
wpa_data = socket.recv(1024)
rescue => e
$stderr.puts 'WARN: unable to gather wpa data: ' + e.inspect
end
# close or next time we attempt to read it will fail.
socket.close

begin
# remove the domain socket file for the client
File.unlink(client_sock_path)
rescue => e
$stderr.puts 'WARN: ' + e.inspect
end

unless wpa_data.nil?
@wifis = Hash[wpa_data.split(/\n/).map\
{|line|
# first, split into pairs delimited by '='
key,value = line.split('=')

# if key is camel-humped then put space in front
# of capped letter
if key =~ /[a-z][A-Z]/
key.gsub!(/([a-z])([A-Z])/,'\\1_\\2')
end

# if key is "id" then rename it.
key.eql?('id') && key = 'wpa_id'

# fix key so that it can be used as a table name
# by replacing spaces with underscores
key.gsub!(' ','_')

# lower case it.
key.downcase!

[key,value]
}]
end
end

编辑:到目前为止,还没有人能够回答这个问题。我认为无论如何我更喜欢 wpa 方法,因为我从中获得了更多数据。也就是说,我想提出的一个问题是,如果有人使用 wpa 代码,请注意它需要升级权限才能读取 wlan 套接字。

编辑^2(完整代码片段):感谢@dasup,我已经能够重构我的类以正确地使用系统 ioctl 提取 bssid 和 essids。 (YMMV 考虑到您的 Linux 发行版的实现、年龄和任何其他可能的不稳定因素——尽管以下代码片段适用于 3.2 和 3.7 内核。)

require 'socket'

class Wpa
attr_accessor :essid, :bssid, :if

def initialize(interface)
@if = interface

puts 'essid: ' + _get_essid.inspect
puts 'bssid: ' + _get_bssid.inspect
end

def _get_essid
# Copied from wireless.h
iwreq = [@if, " " * 32, 32, 0 ].pack('a16pII')

sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
sock.ioctl(0x8B1B, iwreq)

@essid = iwreq.unpack('@16p').pop.strip
end

def _get_bssid
# Copied from wireless.h
# supposing a 16 byte address and 32 byte buffer but I'm totally
# guessing here.
iwreq = [@if, "\0" * 32].pack('a16a32')
sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)

# from wireless.h
# SIOCGIWAP 0x8B15 /* get access point MAC addresses */
sock.ioctl(0x8B15, iwreq) # always get an error: Can't convert string to Integer

@bssid = iwreq.unpack('@18H2H2H2H2H2H2').join(':')
end
end

h = Wpa.new('wlan0')

最佳答案

我对 Ruby 不是很熟悉,但我发现了两个错误:

  • SIOCGIWAP 的十六进制数应不带引号/记号。
  • 数据缓冲区的初始化以接口(interface)名称后的一些尾随字节结束(使用 gdb 调试)。下面给出的初始化有效。

请注意,如果任何数据结构或常量发生更改(IFNAMSIZ、sa_family、struct sockaddr 等),您的代码将会中断。但是,我认为此类更改不会很快发生。

require 'socket'

def _get_bssid(interface)
# Copied from wireless.h
# supposing a 16 byte address and 32 byte buffer but I'm totally
# guessing here.
iwreq = [interface, "\0" * 32].pack('a16a32')
sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)

# from wireless.h
# SIOCGIWAP 0x8B15 /* get access point MAC addresses */
sock.ioctl(0x8B15, iwreq) # always get an error: Can't convert string to Integer

puts iwreq.inspect
end

你会得到一个数组/缓冲区:

  • 您发送的接口(interface)名称,用0x00字节填充,总长度为16字节。
  • 后跟一个struct sockaddr,即一个两字节的标识符0x01 0x00(来自ARPHRD_ETHER?)后跟填充的BSSID 0x00 个字节,总长度为 14 个字节。

祝你好运!

关于ruby - 使用 Ruby 和 ioctl 以编程方式获取 wifi BSSID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19503446/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com