python非特权ICMP

时间:2009-07-27 17:02:55

标签: python ping icmp

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

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

所以从那个方面来看,原本发送没有特权的ICMP ping似乎是不可能的。系统ping命令确实以某种方式进行管理,但其手册页并未阐明如何操作。另一方面,man page for icmp似乎表示有可能:

Non-privileged ICMP
     ICMP sockets can be opened with the SOCK_DGRAM socket type without
     requiring root privileges. The synopsis is the following:

     socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP)

     Datagram oriented ICMP sockets offer a subset of the functionality avail-
     able to raw ICMP sockets. Only IMCP request messages of the following
     types can be sent: ICMP_ECHO, ICMP_TSTAMP or ICMP_MASKREQ.

所以看起来,至少根据icmp,它是允许的。那么为什么所有的python工具都无法做到这一点呢? python工具是否过于笼统,并期望特权套接字上的任何工作都具有特权?是否有可能在C中编写ping函数,可以在没有root权限的情况下ping,并用此扩展python?有没有人这样做过?我只是误解了这个问题吗?

8 个答案:

答案 0 :(得分:12)

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

打开原始套接字后,它通常会丢弃root权限。

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

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

答案 1 :(得分:11)

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

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

请参阅?它由root拥有,并且在权限 - setuserid中具有关键s位。因此,无论用户运行什么,ping 以root身份运行

如果您正在使用带有新“非特权ICMP套接字”的BSD内核,那么看看使用该功能从Python进行ping操作需要什么是有趣的(但这对于任何少用的用户都没有帮助当然是高级内核。

答案 2 :(得分:3)

Modern Linuxes ping使用libcap并要求libcap完成工作。这将检查(capget / set funcitons)并管理权限:

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"将无法工作。也就是说,只要myping实际上是二进制程序。如果是脚本,则必须在脚本解释器上设置此功能。

答案 3 :(得分:1)

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

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

并且如您所知,在数据报套接字上执行此操作会导致错误。

答案 4 :(得分:0)

我不确定是否可以在一个似乎已经回答过的问题中发帖。

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

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

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

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

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

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

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

答案 5 :(得分: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下尝试,但无论如何这个插槽类型看起来不像便携式,至少可以说!

答案 6 :(得分:-2)

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

将Windows上的套接字更改为SOCK_DGRAM会导致“协议不支持100043”异常。所以看起来Windows正确检查是否在TCP而不是UDP上发送icmp。但是,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)

答案 7 :(得分:-8)

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

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