一、前言
盡管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);
}