python 非特权ICMP

发布于 2024-07-29 22:58:06 字数 1810 浏览 5 评论 0原文

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

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

因此从这个角度来看,在没有特殊权限的情况下本机发送 ICMP ping 似乎是不可能的。 系统 ping 命令确实以某种方式进行管理,但其手册页没有说明如何管理。 另一方面,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 语言编写一个无需 root 权限即可 ping 的 ping 函数,并用它扩展 python? 有人这样做过吗? 我刚刚误解了这个问题吗?

While trying to figure out the best method to ping (ICMP) something from python, I came across these questions:

The answers generally boil down to "use this third party module with root privileges" or "use the system's ping command and parse the output". Of the native methods, icmplib and M. Cowles and J. Diemer's ping.py explicitly mention the need for root privileges, as does the scapy manual.

So from that front, natively sending ICMP pings without special privileges seems impossible. The system ping command does manage somehow, but its man page doesn't shed any light on how. The man page for icmp, on the other hand, seems to say it's possible:

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.

So it would seem that, at least according to icmp, it's allowed. So why is it that all the python tools are unable to do this? Are the python tools too general and expect any work on privileged sockets to be privileged? Would it be possible to write a ping function in C that can ping without root privileges, and extend python with this? Has anyone done this? Have I just misunderstood the problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

几味少女 2024-08-05 22:58:06

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

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

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

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

The ping program is installed setuid root. This allows any user to use the program, and still be able to open a raw socket.

After it opens the raw socket, it typically drops root privs.

You generally need a raw socket to do ICMP correctly, and raw sockets are usually restricted. So it's not really python's fault at all.

Regarding the bit about ICMP above, apparently many implementations don't really support those combinations of flags well. So it is likely that most implmentations just use the way they "know" works on most / all architectures.

多孤肩上扛 2024-08-05 22:58:06

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

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

看到了吗? 它由 root 所有,并且在权限中具有关键的 s 位 - setuserid。 因此,无论哪个用户正在运行它,ping 都会以 root 身份运行

如果您使用带有新的“非特权 ICMP 套接字”的 BSD 内核,那么了解使用该功能从 Python 执行 ping 操作需要什么会很有趣(但这对使用不太高级内核的用户没有帮助,当然)。

Here's how /sbin/ping "somehow manages" (on most Unix-y systems):

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

See? It's owned by root and has that crucial s bit in the permission -- setuserid. So, no matter what user is running it, ping runs as root.

If you're using a BSD Kernel with the new "non-privileged ICMP sockets" it would be interesting to see what's needed to use that functionality to ping from Python (but that won't help any user that's on a less advanced kernel, of course).

输什么也不输骨气 2024-08-05 22:58:06

我不确定是否可以在似乎不久前已经得到解答的问题中发布一些内容。

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

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

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

开发人员解释说这将是一个“不会修复”的情况,因为它是一个 UDP ping。

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

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

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

I'm not sure if it is OK to post something in a question that seems it has already been answered a while ago.

I have been searching for the same implementation and found a way to do ICMP via Python with non-root privileges.

python-ping uses the same 'need-root' way to do a ping, but came across a bug report where a user suggested changing SOCK_RAW to SOCK_DGRAM when calling sock :

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

The dev explains this will be a "WONT-FIX" situation because it is a UDP ping rather.

Since I really do not care if ICMP is going out via UDP, I went ahead and got the code and made the proposed changed.

I am now able to do a ping without calling subprocess or needing root!

Again, not sure if posting here after such a long time is OK, but thought this was a better thing!

旧时光的容颜 2024-08-05 22:58:06

现代 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 实际上是一个二进制程序。 如果它是脚本,则必须在脚本解释器上设置此功能。

Modern Linuxes ping uses libcap and asks libcap to do the work.This checks (capget/set funcitons) and manage permissions:

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)   

Lets say you have a "myping" program:

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  

Now do:

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

Now, your "myping" will work without root. That is, as long as myping is in fact a binary program. If it is a script, this capability has to be set on the script interpreter instead.

冷月断魂刀 2024-08-05 22:58:06

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

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

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

Actually, on Windows 7 and Vista you do need to 'Run as Administrator' to do:

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

and as you note, doing it over a datagram socket causes an error.

小草泠泠 2024-08-05 22:58:06

您正在阅读的手册页是关于“BSD Kernel Interfaces Manual”的,似乎来自“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 下尝试,但无论如何,至少可以说,这种套接字类型看起来并不像便携式!

The man page you're reading is about "BSD Kernel Interfaces Manual" and seems to come from "Mac OS X 10.9". I don't have a Mac OS X machine to try, but under Linux, as root or as user I get a permission denied error when I try to open such an 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

Under OpenBSD I get a "Protocol not supported" error:

>>> 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

May be someone could try under MacOS X or other BSDs, but anyway this socket type does not look like portable, to say the least!

伴随着你 2024-08-05 22:58:06

icmplib 模块帮助我进行 ping 操作,而无需以 root 身份运行整个 django 应用程序:
https://pypi.org/project/icmplib/

icmplib module helped me with ping without running whole django app as root:
https://pypi.org/project/icmplib/

人│生佛魔见 2024-08-05 22:58:06

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

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

I am running python under windows 7 ,
Since i am editing and "compiling" the code under Eclipse pydev plugin,
My solution was : Running the eclipse.exe as an administrator : this solved the problem,

This solution is similar to running the cmd as an administrator.

风和你 2024-08-05 22:58:06

我也在寻找一种不使用子进程或需要 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)

I was also looking for an implementation of ping without using subprocess or needing root to ping. My solution needed to be cross-platform, namely Windows and Linux.

Changing the socket on Windows to SOCK_DGRAM results in a "protocol not supported 100043" exception. So it looks like Windows correctly checks to see if icmp is being sent out on TCP rather than UDP. However, windows does not care if it is running as "root" since that is a Linux concept.

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文