web-dev-qa-db-ja.com

PythonでRawソケットを使用するにはどうすればよいですか?

破損したデータを処理するためのネットワークドライバーをテストするアプリケーションを作成しています。そして、生のソケットを使用してこのデータを送信することを考えたので、送信マシンのTCP-IPスタックによって修正されません。

このアプリケーションはLinux上でのみ作成しています。システムコールで生のソケットを使用するコード例がありますが、テストを可能な限り動的に保ち、すべてではないにしてもほとんどをPythonで書きたいと思います。

Pythonでrawソケットを使用する方法の説明と例については、ウェブを少しグーグルで検索しましたが、本当に啓発的なものは見つかりませんでした。アイデアを示す非常に古いコード例ですが、決して機能しません。

私が集めたものから、PythonでのRawソケットの使用法は、セマンティクスはUNIXのrawソケットとほぼ同じですが、パケット構造を定義するstructsがありません。

テストの未加工のソケット部分をPythonではなく、Cでシステムコールを使用して記述し、メインのPythonコード?

34
Avihu Turzion

次のようにします。

まず、ネットワークカードの自動チェックサムを無効にします。

Sudo ethtool -K eth1 tx off

そして、python 2から危険なフレームを送信します(自分でPython 3に変換する必要があります):

#!/usr/bin/env python
from socket import socket, AF_PACKET, SOCK_RAW
s = socket(AF_PACKET, SOCK_RAW)
s.bind(("eth1", 0))

# We're putting together an ethernet frame here, 
# but you could have anything you want instead
# Have a look at the 'struct' module for more 
# flexible packing/unpacking of binary data
# and 'binascii' for 32 bit CRC
src_addr = "\x01\x02\x03\x04\x05\x06"
dst_addr = "\x01\x02\x03\x04\x05\x06"
payload = ("["*30)+"PAYLOAD"+("]"*30)
checksum = "\x1a\x2b\x3c\x4d"
ethertype = "\x08\x01"

s.send(dst_addr+src_addr+ethertype+payload+checksum)

できた.

44
brice

ソケットシステムコール(またはWindowsではWinsocks)は、標準モジュールsocketで既にラップされています: introreference

生のソケットを使用したことはありませんが、このモジュールで使用できるようです:

最後の例は、Windowsで生のソケットを使用して非常に単純なネットワークスニファーを作成する方法を示しています。この例では、インターフェイスを変更するには管理者権限が必要です。

import socket

# the public network interface
Host = socket.gethostbyname(socket.gethostname())

# create a raw socket and bind it to the public interface
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
s.bind((Host, 0))

# Include IP headers
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

# receive all packages
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

# receive a package
print s.recvfrom(65565)

# disabled promiscuous mode
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
10

this はあなたが見つけた古いコードですか?私には賢明に見えますが、私はそれを自分でテストしていません(または生のソケットをあまり使用していません)。 この例 ドキュメントの=は、生のソケットを使用してパケットをスニッフィングする方法を示しており、十分に似ています。

2
unwind

最終的にこのケースの最善の解決策は、Cで全体を書くことでした。これは大きなアプリケーションではないので、そのような小さなものを複数の言語で書くことは大きなペナルティを負うことになります。

Cとpython RAWソケットの両方をいじくり回した後、最終的にはC RAWソケットを好みました。 4ビット以下のみ。pythonはこれに対する支援を定義しませんが、Linux Cにはこのための完全なAPIがあります。

しかし、Pythonでこのほんの少しのヘッダー初期化のみが便利に処理されれば、ここでCを使用したことはないだろうと確信しています。

2
Avihu Turzion
s = socket(AF_PACKET, SOCK_RAW)
s = socket(PF_PACKET, SOCK_RAW)

結果:

[root@localhost python]# tcpdump -i eth0

capture size 96 bytes
11:01:46.850438 

01:02:03:04:05:06 (oui Unknown) > 01:02:03:04:05:06 (oui Unknown), ethertype Unknown (0x0801), length 85:

        0x0000:  5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5b5b  [[[[[[[[[[[[[[[[
        0x0010:  5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5041  [[[[[[[[[[[[[[PA
        0x0020:  594c 4f41 445d 5d5d 5d5d 5d5d 5d5d 5d5d  YLOAD]]]]]]]]]]]
        0x0030:  5d5d 5d5d 5d5d 5d5d 5d5d 5d5d 5d5d 5d5d  ]]]]]]]]]]]]]]]]
        0x0040:  5d5d 5d00 0000 00                        ]]]....
1
gteng

FTR、レベル2アクセス(イーサネット、RadioTap ...)が必要な場合、Windowsでネイティブに実行することはできません(現在)。

クロスプラットフォームの方法でそれらにアクセスしたい場合、行くべき選択はlibpcapとそのPythonバインディング(Npcap/WinPcap Windowsで動作します)。

Libpcapでは、さまざまなレベル(非常に高いまたは非常に低い)で、さまざまなPythonバインディングを使用できます。

私のアドバイスは、 scapyのソケットを使用して、それを解剖に使用していない場合でも)、ネイティブ呼び出しとLibpcap呼び出しの両方を実装します(そして、conf.use_pcap = True

from scapy.all import conf
# conf.use_pcap = True (will be automatic if required)
socket = conf.L2socket(iface="eth0")
# On any platforms, you have `get_if_list()` in `scapy.all` available, to see the ifaces available. You could also ignore it to use the default one
0
Cukic0d