簡體   English   中英

如何在Python中使用原始套接字?

[英]How Do I Use Raw Socket in Python?

我正在編寫一個應用程序來測試網絡驅動程序以處理損壞的數據。 而且我考慮過使用原始套接字發送此數據,因此發送計算機的TCP-IP堆棧將不會對其進行更正。

我僅在Linux上編寫此應用程序。 我有在系統調用中使用原始套接字的代碼示例,但我真的很想保持測試盡可能動態,並使用Python編寫大部分(如果不是全部)測試。

我已經在網絡上搜索了一些關於python中原始套接字用法的解釋和示例,但是還沒有發現真正有意義的東西。 只是一個非常老的代碼示例,演示了這個想法,但絕不起作用。

據我了解,Python的原始套接字用法在語義上與UNIX的原始套接字幾乎相同,但是沒有用於定義數據包結構的struct

我想知道最好不要在Python中編寫測試的原始套接字部分,而在C中使用系統調用,然后從主要Python代碼中調用它,這會更好嗎?

您可以這樣做:

首先,您禁用網卡的自動校驗和:

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)

做完了

套接字系統調用(或Windows中的Winsocks)已經包裝在標准模塊socketintroreference

我從未使用過原始套接字,但看起來它們可以與此模塊一起使用:

最后一個示例顯示了如何在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) 

這個你提到找到舊的代碼? 在我看來,這很明智,但我自己尚未對其進行測試(或大量使用了原始套接字)。 文檔中的此示例顯示了如何使用原始套接字嗅探數據包,並且看起來很相似。

最終,對於這種情況,最好的解決方案是用C編寫整個程序,因為它不是一個大應用程序,所以用一種以上的語言編寫這么小的程序將招致更大的代價。

在對C和python RAW套接字進行了很多玩弄之后,我最終選擇了C RAW套接字。 RAW套接字要求少於8位組的位級修改才能寫入數據包頭。 有時只寫4位或更少。 python對此沒有幫助,而Linux C具有完整的API。

但是我絕對相信,如果僅用Python方便地處理頭文件初始化的這一小部分,我將永遠不會在這里使用C。

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

套接字類應該有所幫助。 如果不是,則需要使用C編寫Python模塊或僅使用C。請參閱http://mail.python.org/pipermail/python-list/2001-April/077454.html

基本Google搜索發現了這一點。

我實際上嘗試了“展開”指出的代碼示例。 AF_PACKET在python 2.7.4中確實為我工作

FTR,如果您希望進行2級訪問(以太網,RadioTap ...),則Windows本身將無法實現(截至今天)。

如果要使用跨平台方法訪問它們,則首選是libpcap及其Python綁定(因為它將在Windows上使用Npcap/WinPcap )。

在各種級別(非常高或非常低)下,您都有各種可用於libpcap的Python綁定。

我的建議是使用scapy的套接字( 即使您不使用它進行解剖 ),也可以實現Native和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

您可以使用此Python庫: rawsocketpy,它允許在第2層上使用原始套接字=>沒有IP / TCP / UDP標頭。

#!/usr/bin/env python
from rawsocketpy import RawSocket

sock = RawSocket("wlp2s0", 0xEEFA)
sock.send("some data")
sock.send("personal data", dest="\xAA\xBB\xCC\xDD\xEE\xFF")

或服務器形式:

#!/usr/bin/env python
from rawsocketpy import RawRequestHandler, RawAsyncServerCallback
import time

def callback(handler, server):
    print("Testing")
    handler.setup()
    handler.handle()
    handler.finish()

class LongTaskTest(RawRequestHandler):
    def handle(self):
        time.sleep(1)
        print(self.packet)

    def finish(self):
        print("End")

    def setup(self):
        print("Begin") 

def main():
    rs = RawAsyncServerCallback("wlp2s0", 0xEEFA, LongTaskTest, callback)
    rs.spin()

if __name__ == '__main__':
    main()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM