2009-07-27 6 views
17

Mentre si cerca di capire il metodo migliore per eseguire il ping (ICMP) qualcosa in pitone, mi sono imbattuta in queste domande:python non privilegiato ICMP

le risposte generalmente si riducono a "utilizzare questo terzo modulo festa con i privilegi di root" o "utilizzare il comando ping del sistema e analizzare l'output". Dei metodi nativi, icmplib e M. Cowles and J. Diemer's ping.py menzionano esplicitamente la necessità di privilegi di root, così come lo scapymanual.

Quindi da quel punto di vista, l'invio nativo di ping ICMP senza privilegi speciali sembra impossibile. Il comando ping di sistema gestisce in qualche modo, ma la sua pagina man non fa luce su come. Il man page for icmp, d'altra parte, sembra dire che è possibile:

 
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.

così sembrerebbe che, almeno secondo ICMP, è consentito. Quindi, perché tutti gli strumenti Python non sono in grado di farlo? Gli strumenti Python sono troppo generici e si prevede che qualsiasi lavoro sui socket con privilegi sia privilegiato? Sarebbe possibile scrivere una funzione di ping in C che possa eseguire il ping senza privilegi di root ed estendere Python con questo? Qualcuno ha fatto questo? Ho appena frainteso il problema?

+0

Quale sistema operativo stai utilizzando? [I recenti kernel di Linux] (https://lkml.org/lkml/2011/5/10/389) e quelli di Mac OS X sono noti per avere socket ICMP non privilegiati. La pagina man che hai trovato proviene da OS X e dovrebbe funzionare. Sono riuscito con un programma [ping ping] non privato con privilegi (https://github.com/lilydjwg/winterpy/blob/master/pylib/icmplib.py) che funziona su Linux (con una modifica alle impostazioni del kernel) ma potrebbe essere necessario qualche aggiustamento su OS X. – lilydjwg

+0

Per Linuix, vedere qui http://stackoverflow.com/questions/8290046/icmp-sockets-linux/20105379#20105379, è necessario un sysctl speciale per poter usare 'socket (AF_INET, SOCK_DGRAM, IPPROTO_ICMP) ' – nos

risposta

11

Il programma ping è installato setuid root. Ciò consente a qualsiasi utente di utilizzare il programma e di essere ancora in grado di aprire un socket non elaborato.

Dopo apre la presa grezzo, gocce tipicamente privs radice.

In genere, è necessario un socket non elaborato per eseguire correttamente ICMP e in genere i socket raw sono limitati. Quindi non è proprio colpa di Python.

Per quanto riguarda il bit su ICMP di cui sopra, apparentemente molte implementazioni non supportano davvero quelle combinazioni di flag. Quindi è probabile che la maggior parte degli impianti utilizzi il modo in cui "sanno" i lavori sulla maggior parte/tutte le architetture.

+0

Ah, questo è un mistero in meno - dal momento che brevi intervalli su ping richiedono ancora sudo, non pensavo che avesse setuid root, ma hai chiaramente ragione su questo. – Markus

+0

Ping non utilizza necessariamente sonde ICMP, né socket grezzi né richiede i privilegi di root. –

11

Ecco come/sbin/ping "riesce in qualche modo" (nella maggior parte dei sistemi Unix-y):

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

Vedi? E 'di proprietà di root e ha quel cruciale s bit nella autorizzazione - setuserid. Quindi, non importa ciò che l'utente è in esecuzione, ping viene eseguito come root.

Se si utilizza un kernel BSD con i nuovi "socket ICMP non privilegiati" sarebbe interessante vedere cosa è necessario utilizzare tale funzionalità per eseguire il ping da Python (ma ciò non aiuterà gli utenti che si trovano su un kernel meno avanzato, ovviamente).

+0

Interessanti, quindi i socket ICMP non privilegiati sono nuovi? Forse cercherò di farlo funzionare da Python quando avrò un po 'di tempo, soprattutto per curiosità. – Markus

+0

Non tutto nuovo ** come una specifica ** (credo che risalga al buon vecchio glorioso BSD 4.3! -), ma un'implementazione _working_ di quella specifica sarebbe piuttosto nuova (e davvero una buona notizia, IMHO). –

0

Non sono sicuro se è corretto pubblicare qualcosa in una domanda che sembra abbia già avuto risposta qualche tempo fa.

Ho cercato la stessa implementazione e ho trovato un modo per fare ICMP tramite Python con privilegi non-root.

python-ping utilizza allo stesso modo 'bisogno-root' per fare un rumore metallico, ma sono imbattuto in un bug report in cui un utente ha suggerito di cambiare SOCK_RAW a SOCK_DGRAM quando si chiama sock:

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

Il dev spiega questo sarà una situazione "WONT-FIX" perché è un ping UDP piuttosto.

Dato che non mi interessa se ICMP sta uscendo tramite UDP, sono andato avanti e ho ottenuto il codice e ho modificato la proposta.

Ora sono in grado di eseguire un ping senza chiamare il sottoprocesso o il root richiesto!

Ancora una volta, non sono sicuro che postare qui dopo tanto tempo sia OK, ma ho pensato che fosse una cosa migliore!

+0

Questo è un approccio interessante. Dovrebbe funzionare bene, ma a rigor di termini, non è più un ping. Ciò significa che i firewall e quelli che hanno una gestione ping speciale potrebbero finire per comportarsi diversamente. – DonGar

+3

Questo approccio non funziona affatto. Non è possibile creare un socket di tipo UDP con protocollo ICMP. Ho ottenuto un EPROTONOSUPPORT (protocollo non supportato). - La ragione è semplice: una tale combinazione di protocolli non esiste. (Il test di risposta è possibile non privilegiato con UDP/TCP, ma ciò richiede più di piccole modifiche come questa.) –

-2

Stavo anche cercando un'implementazione del ping senza l'utilizzo del sottoprocesso o del root. La mia soluzione doveva essere multipiattaforma, ovvero Windows e Linux.

La modifica del socket su Windows su SOCK_DGRAM genera un'eccezione "Protocollo non supportato 100043". Quindi sembra che Windows controlli correttamente per vedere se ICMP viene inviato su TCP anziché su UDP. Tuttavia, a Windows non interessa se è in esecuzione come "root" poiché si tratta di un concetto di 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) 
1

In realtà, su Windows 7 e Vista si ha bisogno di 'Esegui come amministratore' a che fare:

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

e, come si nota, farlo su un socket datagram causa un errore.

-8

Sono in esecuzione pitone sotto Windows 7, Dato che io sono l'editing e la "compilazione" il codice sotto Plug-in Eclipse PyDev, La mia soluzione era: Esecuzione del eclipse.exe come amministratore: questo ha risolto il problema,

Questa soluzione è simile all'esecuzione del cmd come amministratore.

+8

Si prega di non suggerire alle persone di eseguire programmi arbitrari come Amministratore. È così che UAC ha avuto un brutto colpo di scena in primo luogo. La tua risposta inoltre non aiuta per un programma distribuito in produzione. – AdmiralNemo

0

La pagina man che stai leggendo riguarda "BSD Kernel Interfaces Manual" e sembra provenire da "Mac OS X 10.9". Non ho una macchina Mac OS X per provare, ma sotto Linux, come root o come utente ottengo un errore di autorizzazione negata quando provo ad esempio aprire un 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 

Sotto OpenBSD ottengo un "protocollo non supportato" errore:

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

può essere qualcuno potrebbe cercare sotto MacOS X o altri BSD, ma in ogni caso questo tipo di socket non apparire come portatile, per non dire altro!

+0

Si sta facendo male, i messaggi ICMP vengono prelevati dai socket DGRAM come messaggi di errore. Specificare ICMP come protocollo socket su DGRAM è semplicemente sbagliato. –

+0

Faccio quello che l'OP ha fatto ... e chiede. – Pierre

3

Il ping moderno di Linux utilizza libcap e chiede a libcap di eseguire il lavoro.Questo controlla (capget/set funcitons) e gestire le autorizzazioni:

[email protected]:~/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) 

Diciamo che avere un programma "myping":

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

Ora fare:

[email protected]:~/WORK$ getcap ./myping 
./ping = cap_net_raw+ep 

Ora, il vostro " myping "funzionerà senza root. Cioè, finché myping è in realtà un programma binario. Se si tratta di uno script, questa funzione deve essere impostata sull'interprete di script.

+0

punto eccellente, ero quasi disperata che nessuno aveva menzionato le funzionalità. Tuttavia, va notato che se il tuo "programma" è uno script, la capacità deve essere impostata nell'interprete dello script piuttosto che nello script. – 0xC0000022L