Scapy:send函数剖析(参数、返回值、应用)
????????send函數是Scapy中發包的重要函數,使用Scapy的程序員免不了經常與它打交道。但是,我們真的了解它嗎?思此有感,我特地翻閱了源碼,并將自己的分析寫成博客分享給大家。水平不高,如有疑惑請在評論區留言。
????????文檔中是這樣介紹send函數的(懷疑機翻):
scapy.sendrecv.send(x, iface=None, **kargs)
在第三層發送數據包
參數
-
x -- 包裹
-
inter -- 兩個數據包之間的時間(以秒為單位)(默認值為0)
-
loop -- send packet indefinitely (default 0) (bing翻譯為“無限期發送數據包 默認值 0”)
-
count -- 要發送的數據包數(默認無=1)
-
verbose -- 詳細模式(默認無=conf.詳細) (指conf.verb)
-
realtime -- 在發送下一個包之前,請檢查是否已發送了一個包
-
return_packets -- 返回發送的數據包
-
socket -- 要使用的套接字(默認為conf.L3socket(kargs))
-
iface -- 發送數據包的接口
-
monitor -- (不在linux上)以監視模式發送
返回: 沒有 (可能指None)
(源碼附后)
??????? 綠色背景的是我的注釋。
????????不難看出,send函數的參數列表顯式地由三個部分組成:x指要發送的包,iface指發送數據包的接口,還有一個接受不定參數的kargs。
文檔中提到的參數和返回值,經研究后,結果如下:
參數解析:
x:
??????? 類型為_PacketIterable,無默認值。
????????指要發送的包,可傳遞包、迭代器或存有包的列表。不能傳元組(原因不明)。send函數的底層使用for循環遍歷x參數,按理來說可迭代對象均可傳入。
?
inter:
??????? 類型為int或float,默認為0。
????????發包后的停頓時間,以秒為單位。注釋上面標注為int型,實際傳入float也可正常運行。這是因為它調用的是time模塊中的sleep函數。
?
loop:
??????? 類型為int,默認為0。
????????發送數據包的數量,是發包while循環的條件。如果沒有傳遞loop的值,同時也沒有傳遞count的值,則loop值會被設為-1。如果傳了count的值,則loop會被設為-count。每次循環后,loop值加1,加到0時循環停止。
?
count:
??????? 類型為int,默認為None。
??????? 發送包的數量。當count為None時,loop被設為-1,反之被設為-count。注意不要傳入非None、int的值,否則報錯。如果傳入非負數,正常運行。傳入小數,while循環因為loop始終不為0而不會停止。傳入正數,因為send函數底層的做法是將loop賦為-count,在每次循環且loop小于0時執行loop += 1,所以loop始終不為0,故循環不會終止。
?
verbose:
? ? ? ? 類型為int,默認值為conf.verb,即2。
??????? 是否開啟詳細模式。該值為真時,打印發包過程的詳細信息(其實也沒多詳細)。即每法送一個包,打印一個點,并在發包結束之后打印發送的總包數。
?
realtime:
??????? 類型為bool,默認為False。
??????? 是否在發送下一個包之前,檢查是否已發送了一個包。
??????? 這個參數有沒有用我持懷疑態度。在捋完那段繞來繞去的源碼后,我得出一個等式:
第一次發包時間-第一個包構造時的時間>第二次發包時間-第二個包構造時時間,只要滿足這個不等式,send函數就會使用sleep函數阻塞進程第二個包構造時間-第一個包構造時間+第一次發包時間-第二次發包時間。這段代碼是如何檢查是否發送了一個包的,我不得而知。
?
return_packets:
??????? 類型為bool,默認為False。
??????? 是否返回發送的數據包。注意,返回的是一個PacketList對象,不是包。PacketList可以用訪問下標的方法訪問其中的元素。具體的包儲存在res成員中。
?
socket:
??????? 類型為SuperSocket, 默認值為conf.L3socket(kargs))。
????????使用的套接字。當缺省時,send函數會自行處理。
?
iface:
??????? 類型為str,默認值None。該參數用于指定網卡的名稱,網卡的使用由send函數內部完成。如傳入"eth0",send函數就會使用eth0網卡發包。當缺省時,send函數會自行選擇合適的網卡。
?
montor:
??????? (用的Linux,沒找到這個東西)
返回值解析:
??????? 文檔中提到的返回值為None。但經源碼分析之后,send函數的返回值應有兩個:None或PacketList。當return_packets參數為真時,返回PacketList類,反之返回None。
??????? None值不多做解釋。
????????PacketList是定義在plist模塊中的一個類。它的一個父類_PacketList重寫了__repr__(str類進行類型轉換和print函數調用的方法)、__iter__(迭代開始時調用的方法)、__getitem__(索引操作使用的方法)、__add__(重載加法運算符)、__len__(len函數調用的方法)。由此可看出Scapy中對運算符、語句和內置函數的運用不少。
??????? 故此可實現以下操作:
??????? 1.使用print函數打印或調用str類轉換send函數的返回值。
??????? output:
????????????????<PacketList: TCP:0 UDP:0 ICMP:0 Other:1>
??????? 2.像迭代range函數的返回值一樣迭代send函數的返回值。
??????? 3.使用索引調取儲存在send函數返回值的數據包。這并不是對其中res成員的簡單訪問,它還涉及其他返回值,目前還沒有研究。
??????? 4.使用加法運算符在send函數的返回值之間運算。使用這個東西需要注意。如下:
??????? 代碼:
????????????????a = b = send(IP(), return_packets=True)
????????????????d = a + b
????????????????print(d)
??????? output:
??????????????? . (這里有個點)
????????????????Sent 1 packets.
????????????????<PacketList+PacketList: TCP:0 UDP:0 ICMP:0 Other:2>
??????? 如標紅部分所示,多少個PacketList類相加,這里的算式就有多少個元素。故此,如果真的要將send函數的返回值相加,謹慎打印。
??????? 5.使用len函數計算send函數返回值中的數據包數量。
??????? 此外,使用PackekList的summary方法,可以按行打印其中儲存的包的summary方法結果,即按行打印各個包的梗概。
??????? 當然,返回的PacketList有點雞肋,畢竟那是我自己發出去的包。但是,在發送隨機包的時候,的確可能需要返回發送的包。
????????據此,可以總結一些send函數的用法:
1.將count參數設為負值,由此死循環發送數據包,之后用Ctrl+C停止程序
from scapy.all import IP, TCP, sendpacket = IP() / TCP()send(packet, count=-1)output:
┌──(matriller?Hack)-[~/桌面/Practice] └─$ sudo python demo.py ..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................^C Sent 850 packets.????????因為send函數中使用專門的變量來儲存發包數,加上整個發包過程處于try-exept語句中,當按下Ctrl+C時,send函數捕獲KeyboardInterrupt錯誤,之后根據傳參決定是否展示信息,及傳回None或PacketList對象。
????????這可以用于事先不知道要發送多少個包的情況。盡管使用while循環可以獲得同樣的效果,但是調用send函數的花銷很大,每次循環都調用一次send函數,那么程序性能會明顯下降。
2.傳入inter參數,使每次發包之后停頓一段時間
from scapy.all import IP, TCP, send from time import time, sleeppacket = IP() / TCP()t = time() send(packet, count=5, inter=0.5) print(time()-t)t = time() for i in range(5):send(packet)sleep(0.5) print(time()-t)output:
┌──(matriller?Hack)-[~/桌面/Practice] └─$ sudo python demo.py ..... Sent 5 packets. 2.5401618480682373 . Sent 1 packets. . Sent 1 packets. . Sent 1 packets. . Sent 1 packets. . Sent 1 packets. 2.712531805038452????????這個方法很重要。調用send函數的花銷很大,將停頓的工作交由send函數底層去實現可以提高程序性能。在上方的輸出中,僅僅只是發送5個包,使用for循環停頓的比起傳參停頓的已經有明顯的遲鈍。而在網絡編程中,要發送的絕不僅5個包。
3.向verbose傳入假值關閉send函數自身的輸出
from scapy.all import IP, TCP, send from time import time, sleeppacket = IP() / TCP()send(packet, verbose=0)output:
┌──(matriller?Hack)-[~/桌面/Practice] └─$ sudo python demo.py????????沒有了每發一個包都要打印的點和結束時的總數。有時我們在使用Scapy時不希望send函數打印消息到屏幕,那么這個參數會大有用處。
????????由于send函數底層將verbose參數作為if語句的條件,向verbose傳入下列值都可以得到相同的效果:(None不行)
0,0.0,'',b'',False,[],()4.向x參數傳入列表,提升發包速度
from scapy.all import IP, TCP, send from time import time, sleeppacket = [IP() / TCP() for i in range(5)] print(len(packet)) print(type(packet)) print(packet)t = time() send(packet) print(time()-t)t = time() for i in range(5):send(IP() / TCP()) print(time()-t)output:
┌──(matriller?Hack)-[~/桌面/Practice]
└─$ sudo python demo.py
5
<class 'list'>
[<IP? frag=0 proto=tcp |<TCP? |>>, <IP? frag=0 proto=tcp |<TCP? |>>, <IP? frag=0 proto=tcp |<TCP? |>>, <IP? frag=0 proto=tcp |<TCP? |>>, <IP? frag=0 proto=tcp |<TCP? |>>]
.....
Sent 5 packets.
0.03799152374267578
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
0.1679677963256836
????????可以看到,向send函數傳入列表以使其一次性發送,性能比使用for循環多次調用send函數性能要高的多。詳情可以看我的另一篇文章:
Scapy:快速syn洪水攻擊(syn?flood)_Matriller的博客-CSDN博客利用scapy的特性提升進行syn洪水攻擊(syn floor)的速度https://blog.csdn.net/m0_71713477/article/details/128556822?spm=1001.2014.3001.5501
源碼部分:
def __gen_send(s, # type: SuperSocketx, # type: _PacketIterableinter=0, # type: intloop=0, # type: intcount=None, # type: Optional[int]verbose=None, # type: Optional[int]realtime=False, # type: boolreturn_packets=False, # type: bool*args, # type: Any**kargs # type: Any):# type: (...) -> Optional[PacketList]"""An internal function used by send/sendp to actually send the packets,implement the send logic...It will take care of iterating through the different packets"""if isinstance(x, str):x = conf.raw_layer(load=x)if not isinstance(x, Gen):x = SetGen(x)if verbose is None:verbose = conf.verbn = 0if count is not None:loop = -countelif not loop:loop = -1sent_packets = PacketList() if return_packets else Nonep = Nonetry:while loop:dt0 = Nonefor p in x:if realtime:ct = time.time()if dt0:st = dt0 + float(p.time) - ctif st > 0:time.sleep(st)else:dt0 = ct - float(p.time)s.send(p)if sent_packets is not None:sent_packets.append(p)n += 1if verbose:os.write(1, b".")time.sleep(inter)if loop < 0:loop += 1except KeyboardInterrupt:passfinally:try:cast(Packet, x).sent_time = cast(Packet, p).sent_timeexcept AttributeError:passif verbose:print("\nSent %i packets." % n)return sent_packetsdef _send(x, # type: _PacketIterable_func, # type: Callable[[NetworkInterface], Type[SuperSocket]]inter=0, # type: intloop=0, # type: intiface=None, # type: Optional[_GlobInterfaceType]count=None, # type: Optional[int]verbose=None, # type: Optional[int]realtime=False, # type: boolreturn_packets=False, # type: boolsocket=None, # type: Optional[SuperSocket]**kargs # type: Any):# type: (...) -> Optional[PacketList]"""Internal function used by send and sendp"""need_closing = socket is Noneiface = resolve_iface(iface or conf.iface)socket = socket or _func(iface)(iface=iface, **kargs)results = __gen_send(socket, x, inter=inter, loop=loop,count=count, verbose=verbose,realtime=realtime, return_packets=return_packets)if need_closing:socket.close()return results@conf.commands.register def send(x, # type: _PacketIterableiface=None, # type: Optional[_GlobInterfaceType]**kargs # type: Any):# type: (...) -> Optional[PacketList]"""Send packets at layer 3:param x: the packets:param inter: time (in s) between two packets (default 0):param loop: send packet indefinitely (default 0):param count: number of packets to send (default None=1):param verbose: verbose mode (default None=conf.verb):param realtime: check that a packet was sent before sending the next one:param return_packets: return the sent packets:param socket: the socket to use (default is conf.L3socket(kargs)):param iface: the interface to send the packets on:param monitor: (not on linux) send in monitor mode:returns: None"""iface = _interface_selection(iface, x)return _send(x,lambda iface: iface.l3socket(),iface=iface,**kargs)參考文獻:
淺析Python運算符重載_viclee108的博客-CSDN博客_python 運算符重載
scapy.sendrecv — Scapy 2.4.4. 文檔
https://github.com/secdev/scapy/blob/master/scapy/sendrecv.py#L413-L44
?
?
總結
以上是生活随笔為你收集整理的Scapy:send函数剖析(参数、返回值、应用)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 老板必看:1.初创业团队没有激情,咋办?
- 下一篇: 最短路径算法----Floyd-wars