27

在试图找出从 python 中 ping (ICMP) 的最佳方法时,我遇到了以下问题:

答案通常归结为“使用具有 root 权限的第三方模块”或“使用系统的 ping 命令并解析输出”。在本地方法中,icmplibM. Cowles 和 J. Diemer 的 ping.py明确提到了对 root 权限的需求,scapy 手册也是如此。

因此,从这方面来看,在没有特殊权限的情况下本地发送 ICMP ping 似乎是不可能的。system ping 命令确实以某种方式管理,但它的手册页没有说明如何进行。另一方面, icmp的手册页似乎说这是可能的:

非特权 ICMP
     ICMP 套接字可以使用 SOCK_DGRAM 套接字类型打开,而无需
     需要root权限。概要如下:

     套接字(AF_INET,SOCK_DGRAM,IPPROTO_ICMP)

     面向数据报的 ICMP 套接字提供了可用功能的子集
     能够原始 ICMP 套接字。只有以下的 IMCP 请求消息
     可以发送类型:ICMP_ECHO、ICMP_TSTAMP 或 ICMP_MASKREQ。

因此,至少根据 icmp,这似乎是允许的。那么为什么所有的python工具都无法做到这一点呢?python 工具是否过于通用并期望特权套接字上的任何工作都具有特权?是否可以在 C 中编写一个无需 root 权限即可 ping 的 ping 函数,并以此扩展 python?有人做过吗?我只是误解了这个问题吗?

4

9 回答 9

14

ping 程序是安装 setuid root 的。这允许任何用户使用该程序,并且仍然能够打开原始套接字。

在打开原始套接字后,它通常会删除 root 权限。

您通常需要一个原始套接字才能正确执行 ICMP,而原始套接字通常受到限制。所以这根本不是python的错。

关于上面关于 ICMP 的内容,显然许多实现并不能很好地支持这些标志组合。因此,大多数实现很可能只是使用他们“知道”在大多数/所有架构上工作的方式。

于 2009-07-27T17:17:25.417 回答
12

以下是 /sbin/ping “以某种方式管理”的方式(在大多数 Unix-y 系统上):

$ ls -l /sbin/ping
-r-sr-xr-x  1 root  wheel  68448 Jan 26 10:00 /sbin/ping

看?它由setuserid拥有root并在权限中具有关键的一点。s因此,无论哪个用户运行它, ping 都以 root 身份运行

如果您正在使用带有新的“非特权 ICMP 套接字”的 BSD 内核,那么看看使用该功能从 Python ping 需要什么会很有趣(但这不会帮助任何使用不太高级内核的用户,当然)。

于 2009-07-27T17:18:06.460 回答
5

我不确定是否可以在似乎已经回答过一段时间的问题中发布一些内容。

我一直在寻找相同的实现,并找到了一种通过 Python 以非 root 权限执行 ICMP 的方法。

python-ping使用相同的“need-root”方式进行 ping,但遇到了一个错误报告,用户建议在调用时更改SOCK_RAW为:SOCK_DGRAMsock

http://hg.io/delroth/python-ping/issue/1/icmp-without-root-privilege

开发人员解释说这将是“WONT-FIX”的情况,因为它是一个 UDP ping。

因为我真的不在乎 ICMP 是否通过 UDP 出去,所以我继续获取代码并更改了建议的内容。

我现在可以在不调用子进程或需要 root 的情况下进行 ping 操作!

同样,不确定这么长时间后在这里发帖是否可以,但认为这是一件更好的事情!

于 2010-08-05T12:40:24.647 回答
5

现代 Linux ping 使用 libcap 并要求 libcap 完成工作。这会检查(capget/set 功能)并管理权限:

linux@jacax:~/WORK$ ldd /bin/ping  
    linux-gate.so.1 =>  (0xb77b6000)  
    libcap.so.2 => /lib/i386-linux-gnu/libcap.so.2 (0xb7796000)  
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75e7000)  
    /lib/ld-linux.so.2 (0xb77b7000)   

假设您有一个“myping”程序:

linux@jacax:~/WORK$ getcap ./myping    
linux@jacax:~/WORK$   (-> nothing! )  
linux@jacax:~/WORK$ setcap cap_net_raw=ep ./myping  
unable to set CAP_SETFCAP effective capability: Operation not permitted  
linux@jacax:~/WORK$ sudo setcap cap_net_raw=ep ./myping  

现在做:

linux@jacax:~/WORK$ getcap ./myping  
./ping = cap_net_raw+ep

现在,您的“myping”将在没有 root 的情况下工作。也就是说,只要myping实际上是一个二进制程序。如果是脚本,则必须在脚本解释器上设置此功能。

于 2014-11-21T10:30:35.080 回答
2

icmplib 模块帮助我在不以 root 身份运行整个 django 应用程序的情况下进行 ping: https ://pypi.org/project/icmplib/

于 2021-10-27T23:31:03.067 回答
1

实际上,在 Windows 7 和 Vista 上,您确实需要“以管理员身份运行”来执行以下操作:

my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)

正如您所注意到的,通过数据报套接字执行此操作会导致错误。

于 2011-04-06T19:51:46.907 回答
0

您正在阅读的手册页是关于“BSD 内核接口手册”的,似乎来自“Mac OS X 10.9”。我没有要尝试的 Mac OS X 机器,但在 Linux 下,以 root 或用户身份尝试打开此类 ICMP 时出现权限被拒绝错误:

$ strace -e trace=socket python
Python 2.7.5+ (default, Sep 19 2013, 13:48:49) 
[GCC 4.8.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_ICMP)
socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP) = -1 EACCES (Permission denied)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/socket.py", line 187, in __init__
    _sock = _realsocket(family, type, proto)
socket.error: [Errno 13] Permission denied

在 OpenBSD 下,我收到“不支持协议”错误:

>>> import socket
>>> socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_ICMP)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/socket.py", line 187, in __init__
    _sock = _realsocket(family, type, proto)
socket.error: [Errno 43] Protocol not supported

可能有人可以在 MacOS X 或其他 BSD 下尝试,但无论如何这种套接字类型看起来不像是可移植的,至少可以这么说!

于 2014-01-23T12:23:12.380 回答
-1

我也在寻找一种不使用子进程或需要 root 来 ping 的 ping 实现。我的解决方案需要跨平台,即 Windows 和 Linux。

将 Windows 上的套接字更改为 SOCK_DGRAM 会导致“协议不支持 100043”异常。所以看起来 Windows 正确地检查了 icmp 是否是通过 TCP 而不是 UDP 发送的。但是,Windows 并不关心它是否以“root”身份运行,因为这是 Linux 的概念。

if os.name == 'nt':
    #no root on windows
    my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
else:
    #changed to UDP socket...gets around ROOT priv issue
    my_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, icmp)
于 2011-03-19T13:18:43.443 回答
-9

我在 windows 7 下运行 python,因为我在 Eclipse pydev 插件下编辑和“编译”代码,我的解决方案是:以管理员身份运行 eclipse.exe:这解决了问题,

此解决方案类似于以管理员身份运行 cmd。

于 2011-06-08T15:18:33.210 回答