web-dev-qa-db-ja.com

python非特権ICMP

Pythonから何かをping(ICMP)するための最良の方法を見つけようとしているときに、次の質問に出くわしました。

答えは一般的に「root権限でこのサードパーティモジュールを使用する」または「システムのpingコマンドを使用して出力を解析する」に要約されます。ネイティブメソッドのうち、 icmplib および M.CowlesおよびJ.Diemerのping.py は、 scapy と同様に、root権限の必要性について明示的に言及しています。 手動

したがって、その前から、特別な特権なしでICMPpingをネイティブに送信することは不可能に思えます。 system pingコマンドはなんとかして管理しますが、そのマニュアルページはその方法を明らかにしていません。 icmpのmanページ 一方、それは可能だと言っているようです:

非特権ICMP 
 ICMPソケットは、root特権を必要とせずに
 SOCK_DGRAMソケットタイプで開くことができます。概要は次のとおりです。
 
 socket(AF_INET、SOCK_DGRAM、IPPROTO_ICMP)
 
データグラム指向のICMPソケットは、利用可能な機能のサブセットを提供します-
 ICMPソケットを生にすることができます。次の
タイプのIMCP要求メッセージのみを送信できます:ICMP_ECHO、ICMP_TSTAMP、またはICMP_MASKREQ。

したがって、少なくともicmpによれば、それは許可されているように思われます。では、なぜすべてのpythonツールがこれを実行できないのですか?pythonツールは一般的すぎて、特権ソケットでの作業が特権化されることを期待しているのですか?ルート権限なしでpingできるping関数をCで記述し、これでpythonを拡張することは可能でしょうか?誰かがこれを行ったことがありますか?問題を誤解しただけですか?

21
Markus

Pingプログラムはsetuidrootにインストールされます。これにより、すべてのユーザーがプログラムを使用しながら、rawソケットを開くことができます。

Rawソケットを開いた後、通常はrootprivを削除します。

通常、ICMPを正しく実行するにはrawソケットが必要であり、rawソケットは通常制限されています。したがって、それは実際にはPythonのせいではありません。

上記のICMPについて少し言えば、明らかに多くの実装はこれらのフラグの組み合わせを実際にはうまくサポートしていません。したがって、ほとんどの実装では、ほとんど/すべてのアーキテクチャで「知っている」動作を使用している可能性があります。

13
Christopher

/ 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を実行するために何が必要かを確認するのは興味深いでしょう(ただし、それは役に立ちません)もちろん、それほど高度でないカーネルを使用しているユーザー)。

11
Alex Martelli

最新のLinuxの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
Pablo

実際、Windows 7およびVistaでは、次のことを行うために「管理者として実行」する必要があります。

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

お気づきのように、データグラムソケットを介して実行するとエラーが発生します。

1
Oli

しばらく前に回答済みのように見える質問に何かを投稿してもよいかどうかはわかりません。

私は同じ実装を探していて、root以外の権限でPythonを介してICMPを実行する方法を見つけました。

python-pingは同じ 'need-root'方法を使用してpingを実行しますが、ユーザーがsockを呼び出すときにSOCK_RAWSOCK_DGRAMに変更することを提案したバグレポートに遭遇しました。

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

開発者は、これはむしろUDP pingであるため、これは「WONT-FIX」状況になると説明しています。

ICMPがUDP経由で送信されるかどうかは本当に気にしないので、先に進んでコードを取得し、提案を変更しました。

サブプロセスを呼び出したり、rootを必要とせずに、pingを実行できるようになりました。

繰り返しになりますが、このような長い時間の後にここに投稿しても大丈夫かどうかはわかりませんが、これはより良いことだと思いました!

1
alfredodeza

あなたが読んでいるmanページは「BSDカーネルインターフェースマニュアル」に関するもので、「Mac OSX10.9」から来ているようです。試すMacOS 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

誰かがMacOSXや他のBSDで試すことができるかもしれませんが、とにかくこのソケットタイプは控えめに言ってもポータブルのようには見えません!

0
Pierre