最近工作需要做大規模的掃瞄,需要自己根據指紋寫乙個掃瞄引擎,其中碰到了無數的坑,最後勉強算的過去,特地寫寫部落格總結一下各種坑和思路。
一開始自然而然想到的就是這個掃瞄模型,利用python中的同步佇列結合多執行緒發包、收包、寫操作。大致模型如下:
class
worker
(thread):
def__init__
(self, queue):
self.queue = queue
defrun(self):
while
true:
ip = self.queue.get()
sock.send()
recv = sock.recv(buf_size)
....
do sth....
....
self.queue.task_done()
defmain
(): ...
worker = worker(queue)
work.deamon = true
work.start()
queue.join() # 佇列同步
...
然而事實證明效率真的很低,只能發出可憐的幾百pps,4m
頻寬都佔不滿。各位如果想做大規模掃瞄,我說的大規模掃瞄是指上億的ip掃瞄,就別考慮這種方法了。
總結一下原因,主要是執行緒太多,切換時間非常耗費cpu,並且由於gil
的存在,效率可想而知。其次就是由於ip太多,不能全部放入佇列中,必須在main函式中做個緩衝區,然後放入同步佇列,頻繁queue.join()
的結果是狀態為done的執行緒在等待慢執行緒的情景增多,效率自然就不高了,由於以上原因導致的效率低下,網路的io延遲根本不算什麼。
後來又想用celery做非同步的任務,分離網路io和本地io,把執行緒中本地耗時長的io操作分離出來,放到celery當中非同步執行,這樣可以加快發包收包執行緒的速度。結果發現更慢,建議不要用celery處理非常耗時的後台任務,感覺好坑….
class
sender
(thread):
def__init__
(self, sock):
self.sock = sock
defrun(self):
for ip in list:
pack = package_create()
self.sock.sendto(pack, server)
....
do sth ...
....
class
receiver
(thread):
def__init__
(self, sock):
self.sock = sock
defrun(self):
while
true:
recv = self.sock.recvfrom(buf_size)
handle_recv_package(recv)
....
do sth ...
....
defmain
(): sender = sender(sock)
recver = receiver(sock)
....
do sth ...
....
sock.close()
比較麻煩的是,這種模式需要自己對報文進行組裝、傳送、解析接收的報文等工作。回報是,效率大大提高,輕鬆3k~4kpps(4m/1 cpu/2g mem),頻寬基本佔滿。
主要提公升的空間在以下方面:
優化做好了,現有的頻寬佔滿了,這時候,瓶頸就是頻寬,就要換個更好的頻寬,增加速度。另外,在測試的過程中,鄙人發現網絡卡傳送udp包的速度比tcp慢多了,用了兩台機器測試,結論一致。
用python實現乙個埠掃瞄器
最簡單的埠掃瞄工具使用tcp連線掃瞄的方式,即利用作業系統原生的網路功能,且通常作為syn掃瞄的替代選項。nmap將這種模式稱為連線掃瞄,因為使用了類似unix系統的connect 命令。如果該埠是開放的,作業系統就能完成tcp三次握手,然後埠掃瞄工具會立即關閉剛建立的該連線,防止拒絕服務攻擊。us...
用C寫的乙個掃瞄器原始碼
include include 編譯時需使用的庫 pragma comment lib,wsock32.lib select 成員定義 define zero fd set 0 變數定義 int maxth,scanok,scannum int portip,hoststart,hoststop,s...
python實現乙個簡單的c段掃瞄器
import threading import time import subprocess def ping ip subprocess.popen 建立子程序 ping c 2 指定ping的次數 count為2 指定bash c是因為linux中可能有很多shell,bash c 是為了保證命...