天天看點

WinPcap發送資料包

一、前言

盡管WinPcap從名字上來看表明他的主要目的是捕獲資料包,但是他還為原始網絡提供了一些其他的功能,其中之一就是使用者可以發送資料包,這也就是本節的主要内容。需要指出的是原來的libpcap并不提供資料包的發送功能,這裡所說的功能都是WinPcap的擴充功能,是以并不能夠工作在UNIX下。

二、代碼詳解

用​

​pcap_sendpacket()​

​來發送一個資料包,這個函數需要參數:

  • 一個裝有要發送資料的緩沖區;
  • 要發送的長度;
  • 一個擴充卡;
注意緩沖區中的資料将不被核心協定處理,隻是作為最原始的資料流被發送,是以我們必須填充好正确的協定頭以便正确的将資料發送
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>

#define HAVE_REMOTE
#include "pcap.h"

#ifndef WIN32
    #include <sys/socket.h>
    #include <netinet/in.h>
#else
    #include <winsock2.h>
    #include <ws2tcpip.h>
#endif

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();



    pcap_t* fp;   //定義檔案句柄
    char errbuf[PCAP_ERRBUF_SIZE];
    u_char packet[100];
    int i;

    //檢查指令行參數,是否帶有檔案名
    if(argc != 2) {
        qDebug()<<"usage: %s filename"<<argv[0];
    }

    //打開指定網卡
    if((fp = pcap_open_live(argv[1],100,1,1000,errbuf)) == NULL) {
        qDebug()<<stderr<<"Error opening adapter: "<<errbuf;
    }

    //假設網絡環境為ethernet,我們把目的MAC設為1:1:1:1:1:1
    packet[0] = 1;
    packet[1] = 1;
    packet[2] = 1;
    packet[3] = 1;
    packet[4] = 1;
    packet[5] = 1;

    //假設源MAC為2:2:2:2:2:2
    packet[6] = 2;
    packet[7] = 2;
    packet[8] = 2;
    packet[9] = 2;
    packet[10] = 2;
    packet[11] = 2;

    //填充發送包的剩餘部分
    for(int i=12; i<100; ++i) {
        packet[i] = i%256;
    }

    //發送包
    pcap_sendpacket(fp,packet,100);

    return a.exec();
}      

​pcap_sendpacket()​

​隻是提供了一個簡單的直接的發送資料的方法,而發送隊列提供了一個進階的、強大的、和最優的機制來發送一組資料包,隊列實際上是一個裝有要發送資料的一個容器,他又一個最大值來表明它能夠容納的最大比特數。

​pcap_sendqueue_alloc()​

​用來建立愛你一個隊列,并指定該隊列的大小。

一旦隊列被建立就可以調用​

​pcap_sendqueue_queue()​

​​來将資料存儲到隊列中,這個函數接受一個帶有時間戳和長度的​

​pcap_pkthdr​

​​結構和一個裝有資料報的緩沖區。這些參數同樣也應用于​

​pcap_next_ex()​

​​和​

​pcap_handler()​

​​中,是以給要捕獲的資料包或要從檔案讀取的資料包排隊就是​

​pcap_sendqueue_queue()​

​的事情了。

WinPcap調用​

​pcap_sendqueue_transmit()​

​來發送資料包,注意,第三個參數如果非零,那麼發送将是同步的,這将站用很大的CPU資源,因為發生在核心驅動的同步發送是通過"brute force"loops的,但是一般情況下能夠精确到微秒。

需要指出的是用​

​pcap_sendqueue_transmit()​

​​來發送比用​

​pcap_sendpacket()​

​來發送一系列的資料要高效的多,因為他的資料是在核心級上被緩沖。

#include <stdlib.h>
#include <stdio.h>

#include <pcap.h>

void usage();

void main(int argc, char **argv) {
    pcap_t *indesc,*outdesc;
    char error[PCAP_ERRBUF_SIZE];
    FILE *capfile;
    int caplen, sync;
    u_int res;
    pcap_send_queue *squeue;
    struct pcap_pkthdr *pktheader;
    u_char *pktdata;

    /* Check the validity of the command line */
    if (argc <= 2 || argc >= 5)
    {
        usage();
        return;
    }
        
    /* 得到檔案長度 */
    capfile=fopen(argv[1],"rb");
    if(!capfile){
        printf("Capture file not found!\n");
        return;
    }
    
    fseek(capfile , 0, SEEK_END);
    caplen= ftell(capfile)- sizeof(struct pcap_file_header);
    fclose(capfile);
            
    /* 檢查確定時間戳被忽略 */
    if(argc == 4 && argv[3][0] == 's')
        sync = TRUE;
    else
        sync = FALSE;

    /* Open the capture */
    if((indesc = pcap_open_offline(argv[1], error)) == NULL){
        fprintf(stderr,"\nError opening the input file: %s\n", error);
        return;
    }

    /* Open the output adapter */
    if((outdesc = pcap_open_live(argv[2], 100, 1, 1000, error) ) == NULL)
    {
        fprintf(stderr,"\nError opening adapter: %s\n", error);
        return;
    }

    /* 檢測MAC類型 */
    if(pcap_datalink(indesc) != pcap_datalink(outdesc)){
        printf("Warning: the datalink of the capture differs from the one of the selected interface.\n");
        printf("Press a key to continue, or CTRL+C to stop.\n");
        getchar();
    }

    /* 給對列配置設定空間 */
    squeue = pcap_sendqueue_alloc(caplen);

    /* 從檔案獲得包來填充隊列 */
    while((res = pcap_next_ex( indesc, &pktheader, &pktdata)) == 1){
        if(pcap_sendqueue_queue(squeue, pktheader, pktdata) == -1){
            printf("Warning: packet buffer too small, not all the packets will be sent.\n");
            break;
        }
    }

    if(res == -1){
        printf("Corrupted input file.\n");
        pcap_sendqueue_destroy(squeue);
        return;
    }

    /* 傳送隊列資料 */
    
    if((res = pcap_sendqueue_transmit(outdesc, squeue, sync)) < squeue->len)
    {
        printf("An error occurred sending the packets: %s. Only %d bytes were sent\n", error, res);
    }
    
    /* free the send queue */
    pcap_sendqueue_destroy(squeue);

    return;
}


void usage()
{
    printf("\nSendcap, sends a libpcap/tcpdump capture file to the net. Copyright (C) 2002 Loris Degioanni.\n");
    printf("\nUsage:\n");
    printf("\t sendcap file_name adapter [s]\n");
    printf("\nParameters:\n");
    printf("\nfile_name: the name of the dump file that will be sent to the network\n");
    printf("\nadapter: the device to use. Use \"WinDump -D\" for a list of valid devices\n");
    printf("\ns: if present, forces the packets to be sent synchronously, i.e. respecting thetimestamps in the dump file. This option will work only under Windows NTx.\n\n");

    exit(0);
}