[Python]使用Winpcapy來送自定義的網路封包

最近因為公司的新客戶需求,開始研究起Python(是的!又一個新語言)。客戶要用Python寫的Socket Client腳本檔,連結我們的產品Server。好在學了之後發現Python真是一個非常好入門的直譯式語言,初期不用考慮繁瑣複雜的環境和UI,是一套很好學習邏輯的語言。

以前都是透過用C++寫的Client API負責連接Server,UI端再去呼叫dll來用,之前TCL腳本,C#,C++程式都是去呼叫dll,所以一開始Python也是用這種方式連結。而老闆就是覺得這樣太侷限,突發奇想問能不能用純Python方式,不用呼叫dll。結論是當然可以,只是必須整個重寫,而且理論上Client端就能跨平台了。寫出來Python版的API之後,已經丟給TC驗證。

閒暇就在想能不能不透過Socket,直接叫網卡送非TCP/IP標頭的自定包。就像我們公司產品一樣,MAC位址都可以自己訂這樣。在Windows底下,有個Winpcap的玩意可以做到,而Python相對應的就是Winpcapy了。只可惜Winpcapy是封裝Winpcap,用ctype方式去呼叫Winpcap dll,包成Python方式呼叫而已,所以,還是不能跨平台。

Winpcapy下載位置

Winpcapy引用非常簡單,底下宣告,就可以直接用了:
    from winpcapy import *
Winpcapy範例非常完整,直接把兩個範例(basic_dump和sendpack)合起來改。

先用basic_dump範例的抓取網卡資訊名稱,再當作sendpack裡頭pcap_open_live function的參數。
    alldevs=POINTER(pcap_if_t)()
    errbuf= create_string_buffer(PCAP_ERRBUF_SIZE)
    ## Retrieve the device list
    if (pcap_findalldevs(byref(alldevs), errbuf) == -1):
        print ("Error in pcap_findalldevs: %s\n" % errbuf.value)
        sys.exit(1)
    d=alldevs
    #因為電腦對外網卡腦是第一個,不用判斷next直接抓
    d=d.contents
    #Open the adapter
    fp = pcap_open_live(d.name,65536,1,1000,errbuf)
造一個特定包。這邊只動到MAC
    u_char packet[100];
    packet[0]=0x00
    packet[1]=0x22
    packet[2]=0xA2
    packet[3]=0x00
    packet[4]=0x00
    packet[5]=0x01
    packet[6]=0x00
    packet[7]=0x22
    packet[8]=0xA2
    packet[9]=0x00
    packet[10]=0x00
    packet[11]=0x02
迴圈送出並計算時間
    bmillis = int(round(time.time() * 1000))
    ## Send down the packet
    for i in range(0,1000):
        if (pcap_sendpacket(fp,packet,100) != 0):
            print ("\nError sending the packet: %s\n" % pcap_geterr(fp))
            sys.exit(3)
    emillis = int(round(time.time() * 1000))
    print "TotalTime(ms) = %d" %(emillis-bmillis)
打1000個包時間約217ms,換算大約1秒鐘可以打出包長100 bytes的包4500多個。
以我網卡100Mb網卡速率,最多可以打出(100,000,000/8)/(100+20)=104166個包。換算效率是4500/104166=4.32%。還蠻差的。不過因為使用Winpcap等於用軟體計算crc,Append在包最後面再送出,因此這速度可以了。反正client端我們是用來送控制包,firmware也沒法處理這樣快又多的命令。只是不能拿來收送包測自訂包throughput了。

0 意見:

搜尋此網誌

總網頁瀏覽量

TK呱呱

Made with by TK