python ping icmp

Python ICMP sin privilegios



ping (8)

Mientras intentaba descubrir el mejor método para hacer ping (ICMP) desde Python, encontré estas preguntas:

Las respuestas generalmente se reducen a "usar este módulo de terceros con privilegios de root" o "usar el comando ping del sistema y analizar la salida". De los métodos nativos, icmplib y M. Cowles y J. Diemer ping.py mencionan explícitamente la necesidad de privilegios de root, al igual que el manual scapy .

Entonces, desde ese frente, el envío nativo de pings ICMP sin privilegios especiales parece imposible. El comando ping del sistema se maneja de alguna manera, pero su página de manual no arroja ninguna luz sobre cómo. La página de manual de icmp , por otro lado, parece decir que es posible:

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.

Así que parece que, al menos de acuerdo con icmp, está permitido. Entonces, ¿por qué es que todas las herramientas de python no pueden hacer esto? ¿Las herramientas de Python son demasiado generales y esperan que cualquier trabajo en sockets privilegiados sea privilegiado? ¿Sería posible escribir una función de ping en C que pueda hacer ping sin privilegios de root, y extender Python con esto? ¿Alguien ha hecho esto? ¿Acaso he malinterpretado el problema?


Aquí se explica cómo / sbin / ping "gestiona de alguna manera" (en la mayoría de los sistemas Unix-y):

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

¿Ver? Es propiedad de root y tiene ese bit crucial en el permiso: setuserid. Entonces, no importa qué usuario lo esté ejecutando, ping se ejecuta como root .

Si está utilizando un Kernel BSD con los nuevos "sockets ICMP sin privilegios" sería interesante ver qué se necesita para usar esa funcionalidad para hacer ping desde Python (pero eso no ayudará a ningún usuario que esté en un kernel menos avanzado. por supuesto).


El ping moderno de Linux usa libcap y le pide a libcap que haga el trabajo. Esto comprueba (funciones de capget / set) y administra los permisos:

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)

Digamos que tienes un programa de "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

Ahora haz:

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

Ahora, su "myping" funcionará sin root. Es decir, siempre que myping sea ​​de hecho un programa binario. Si se trata de un script, esta función debe configurarse en el intérprete de script.


El programa ping está instalado setuid root. Esto permite a cualquier usuario utilizar el programa y aún así poder abrir un socket en bruto.

Después de que abre el socket en bruto, por lo general, elimina los privilegios de raíz.

Por lo general, necesita un socket en bruto para hacer ICMP correctamente, y los sockets en bruto generalmente están restringidos. Así que no es realmente culpa de Python en absoluto.

Con respecto a lo que se mencionó anteriormente sobre ICMP, aparentemente muchas implementaciones no son compatibles con esas combinaciones de indicadores. Por lo tanto, es probable que la mayoría de las implementaciones solo usen la forma en que "saben" funcionan en la mayoría / todas las arquitecturas.


En realidad, en Windows 7 y Vista es necesario ''Ejecutar como administrador'' para hacer:

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

y como se nota, hacerlo sobre un socket de datagrama causa un error.


Estoy ejecutando python bajo Windows 7, ya que estoy editando y "compilando" el código bajo el complemento pydev de Eclipse, mi solución fue: Ejecutar el eclipse.exe como administrador: esto resolvió el problema,

Esta solución es similar a ejecutar el cmd como administrador.


La página de manual que está leyendo trata sobre el "Manual de interfaces de núcleo de BSD" y parece provenir de "Mac OS X 10.9". No tengo una máquina con Mac OS X para probar, pero bajo Linux, como root o como usuario , obtengo un error de permiso denegado cuando intento abrir un ICMP de este tipo:

$ 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

Bajo OpenBSD recibo un error de "Protocolo no compatible":

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

Puede ser que alguien pueda probar con MacOS X u otros BSD, pero de todos modos este tipo de socket no parece portátil, por decir lo menos.


No estoy seguro de si está bien publicar algo en una pregunta que parece que ya se ha respondido hace un tiempo.

He estado buscando la misma implementación y encontré una forma de hacer ICMP a través de Python con privilegios no root.

python-ping utiliza la misma forma de ''root de necesidad'' para hacer un ping, pero se encontró con un informe de error en el que un usuario sugirió cambiar SOCK_RAW a SOCK_DGRAM al llamar a sock :

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

El desarrollador explica que esta será una situación "WONT-FIX" porque es más bien un ping UDP.

Como realmente no me importa si ICMP está saliendo a través de UDP, seguí adelante y obtuve el código e hice el cambio propuesto.

¡Ahora puedo hacer un ping sin llamar al subproceso o sin necesidad de root!

Nuevamente, no estoy seguro si publicar aquí después de tanto tiempo está bien, ¡pero pensé que esto era algo mejor!


También estaba buscando una implementación de ping sin utilizar subproceso o necesitar root para hacer ping. Mi solución necesitaba ser multiplataforma, a saber, Windows y Linux.

Cambiar el socket en Windows a SOCK_DGRAM da como resultado una excepción de "protocolo no compatible 100043". Así que parece que Windows comprueba correctamente si se está enviando icmp en TCP en lugar de UDP. Sin embargo, a Windows no le importa si se ejecuta como "raíz" ya que es un concepto de 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)