[英]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)已經包裝在標准模塊socket
: intro , reference 。
我從未使用過原始套接字,但看起來它們可以與此模塊一起使用:
最后一個示例顯示了如何在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.