Python - 使用 C 类型和本机 ioctl() 获取 Mac 地址会产生未知结果
Posted
技术标签:
【中文标题】Python - 使用 C 类型和本机 ioctl() 获取 Mac 地址会产生未知结果【英文标题】:Python - Getting Mac address with C types and native ioctl() yields uknown results 【发布时间】:2013-02-07 23:11:40 【问题描述】:我正在开发一个迷你模块,以便在 python 中为我的大学作业(不是说这是实际作业,只是为了澄清)提供低级网络接口访问权限。实际的分配是在 C 中完成的,但在那之后我决定使用 ctypes 进行一些练习并启动 lib,目标是 Linux 和 Python 2.7。
我已经知道 Python 3.3 公开了很多我试图涵盖的功能,并且自 arround 2.3 版左右以来它已经有一个 fcntl.ioctl 模块(实际上并没有确切的版本无关紧要,只是它存在于 2.7 中),但这个任务是为了学习。
我遇到的问题很简单。我已经根据 C 对应物的布局定义了以下类(为了清楚起见,请忍受长 sn-p ):
class struct_ifmap(Structure):
_fields_ = [
('mem_start', c_ulong),
('mem_end', c_ulong),
('base_addr', c_ushort),
('irq', c_ubyte),
('dma', c_ubyte),
('port', c_ubyte),]
class union_ifreq_anon(Union):
_fields_ = [
('ifr_addr', struct_sockaddr),
('ifr_dstaddr', struct_sockaddr),
('ifr_broadaddr', struct_sockaddr),
('ifr_netmask', struct_sockaddr),
('ifr_hwaddr', struct_sockaddr),
('ifr_flags', c_short),
('ifr_ifindex', c_int),
('ifr_metric', c_int),
('ifr_mtu', c_int),
('ifr_map', struct_ifmap),
('ifr_slave', c_char),
('ifr_newname', c_char),
('ifr_data', c_char_p),
('raw', c_short * 15),]
class struct_ifreq(Structure):
__IFNAMSIZ = 16
_anonymous_ = [
('u'),]
_fields_ = [
('ifr_name', c_char * __IFNAMSIZ),
('u', union_ifreq_anon),]
还有以下功能:
def _getfahwdraddr(name):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
socket.IPPROTO_IP)
ifr = struct_ifreq()
ifr.ifr_name = name
result = _libc.ioctl(sock.fileno(), 0x8927, pointer(ifr))
if result != 0:
raise OSError(get_errno())
return ''.join(['%02x:' % pair for pair in \
ifr.ifr_hwaddr.sa_data[0:6]])[:-1]
这给出的输出是 -6c:39:-1b:XX:XX:XX,这与真正的 MAC 不对应,即 94:39:e5:XX:XX:XX。一个线索可能是某些元素是正确的,但正如您所看到的,输出是错误的。我不知道为什么。
令人惊讶的是,我在 SO 中发现了一个类似的问题,其目的几乎相同,但使用了打包结构和 python 自己的 ioctl。它只是工作:Getting MAC Address。不过,我的问题是如何正确表示和使用 ctype 结构。
【问题讨论】:
您看过source 以了解Python 的ioctl 是如何工作的吗?并不是说这会直接回答您的问题,但它非常方便。 谢谢。我去看看。看实物永远不会有什么坏处。 抱歉,我好像链接到 2.7 源而不是 3.3。但希望你能从那里找到自己的路。无论如何,我看不出您的代码有任何明显错误,除了……我看不出info[18:24]
与ifr_hwaddr.sa_data[0:6]
的字节数如何相同。因此,如果您链接的答案是正确的……您确定您正在寻找与该答案相同的领域吗?
等一下,没关系,我知道了。
旁注:您几乎从不需要或不想在 Python 中使用反斜杠延续。您可以通过缩进续行来继续括号/括号表达式。
【参考方案1】:
你得到了正确的答案,只是你的格式不正确:
-6c:39:-1b:XX:XX:XX
这是显示有符号字节。你想要的结果是这样的:
94:39:e5:XX:XX:XX
这与无符号字节的值完全相同。比较:
>>> hex(0x100-0x6c)
'0x94'
>>> hex(0x100-0x1b)
'0xe5'
你没有展示你是如何定义struct_sockaddr
的。您可以在那里修复它,只需使用无符号类型,例如 c_uint8 * 14
代替 c_char * 14
。
或者,您可以在格式化时进行投射:
return ''.join(['%02x:' % c_uint8(pair).value for pair in
ifr.ifr_hwaddr.sa_data[0:6]])[:-1]
或其他 30 种解决相同问题的方法。
【讨论】:
这就是为什么代码审查真的很有帮助:) 再次非常感谢。我不得不承认这是我绝望的。甚至没有考虑输出中出现的减号,天哪。以上是关于Python - 使用 C 类型和本机 ioctl() 获取 Mac 地址会产生未知结果的主要内容,如果未能解决你的问题,请参考以下文章
Linux C语言 获取本机(所有网卡)IP地址(IPV4)
python-daemon 阻止对 ctypes 链接的 C 用户库的 ioctl 调用