|
WinPcap 이라는 이름이 패킷 캡쳐 라이브러리라는 목적이 분명히 드러나긴 하지만, 가공되어지지 않은 네트워크를 지원되기 위한 다른 유용한 기능도 있다. 그 중에서도, 사용자는 패킷들을 전송하기 위한 완벽한 기능들이 있다는 것을 확인할 수 있다. 현재 오리지날 libpcap 라이브러리는 패킷전송을 지원하지 않는다. 따라서 여기에 나타난 모든 기능들은 WinPcap에 추가된 것이고 Unix에서는 지원되지 않는다. Sending a single packet with pcap_sendpacket() 패킷을 전송할 수 있는 가장 간단한 방법을 부분부분 코드로 보여주고 있다. 어댑터를 개방한 후에, hand-crafted 패킷을 전송하기 위해 pcap_sendpacket()을 호출 하였다. pcap_sendpacket()은 전송하려는 데이타, 버퍼의 길이 그리고 어댑터의 아규먼트들을 갖는다. 버퍼에 있는 데이타는 어떤 조작없이 그대로 전송된다는 것을 기억해라. 이것이 의미하는 것은 무언가를 제대로 전송하기 위해서는 응용프로그램이 올바른 프로토콜 헤더들을 생성해야 한다는 것을 의미하다.
|
VC 6 환경에서 빌드되어 있음.
컴파일전,
Project Settings -> C/C++ -> Category(General) 항목의
Project Options /D "_WSPIAPI_COUNTOF" 를 추가해야 함.
#define WPCAP
#define HAVE_REMOTE#include <stdlib.h>
#include <stdio.h>
#include <pcap.h>#pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "ws2_32.lib") void main(int argc, char **argv) { pcap_t *fp; char errbuf[PCAP_ERRBUF_SIZE]; u_char packet[100]; int i; /* Check the validity of the command line */ if (argc != 2) { printf("usage: %s interface (e.g. 'rpcap://eth0')", argv[0]); return; } /* Open the output device */ if ( (fp= pcap_open(argv[1], // name of the device 100, // portion of the packet to capture (only the first 100 bytes) PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 1000, // read timeout NULL, // authentication on the remote machine errbuf // error buffer ) ) == NULL) { fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", argv[1]); return; } /* Supposing to be on ethernet, set mac destination to 1:1:1:1:1:1 */ packet[0]=1; packet[1]=1; packet[2]=1; packet[3]=1; packet[4]=1; packet[5]=1; /* set mac source to 2:2:2:2:2:2 */ packet[6]=2; packet[7]=2; packet[8]=2; packet[9]=2; packet[10]=2; packet[11]=2; /* Fill the rest of the packet */ for(i=12;i<100;i++) { packet[i]=i%256; } /* Send down the packet */ if (pcap_sendpacket(fp, packet, 100 /* size */) != 0) { fprintf(stderr,"\nError sending the packet: \n", pcap_geterr(fp)); return; } return; }
Send queues
While pcap_sendpacket() offers a simple and immediate way to send a single packet, send queues provides an advanced, powerful and optimized mechanism to send a collection of packets. A send queue is a container for a variable number of packets that will be sent to the network. It has a size, that represents the maximum amount of bytes it can store.
A send queue is created calling the pcap_sendqueue_alloc() function, specifying the size of the new send queue.
Once the send queue is created, pcap_sendqueue_queue() can be used to add a packet to the send queue. This function takes a pcap_pkthdr with the timestamp and the length and a buffer with the data of the packet. These parameters are the same as those received by pcap_next_ex() and pcap_handler(), therefore queuing a packet that was just captured or read from a file is a matter of passing these parameters to pcap_sendqueue_queue().
To transmit a send queue, WinPcap provides the pcap_sendqueue_transmit() function. Note the third parameter: if nonzero, the send will be synchronized, i.e. the relative timestamps of the packets will be respected. This operation requires a remarkable amount of CPU, because the synchronization takes place in the kernel driver using "busy wait" loops. Although this operation is quite CPU intensive, it often results in very high precision packet transmissions (often around few microseconds or less).
Note that transmitting a send queue with pcap_sendqueue_transmit() is much more efficient than performing a series of pcap_sendpacket(), because the send queue is buffered at kernel level drastically decreasing the number of context switches.
When a queue is no longer needed, it can be deleted with pcap_sendqueue_destroy() that frees all the buffers associated with the send queue.
The next program shows how to use send queues. It opens a capture file with pcap_open_offline(), then it moves the packets from the file to a properly allocated send queue. At his point it transmits the queue, synchronizing it if requested by the user.
Note that the link-layer of the dumpfile is compared with the one of the interface that will send the packets using pcap_datalink(), and a warning is printed if they are different -- it is important that the capture-file link-layer be the same as the adapter's link layer for otherwise the tranmission is pointless.
/* * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino, CACE Technologies * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include <stdlib.h> #include <stdio.h> #include <pcap.h> #include <remote-ext.h> void usage(); void main(int argc, char **argv) { pcap_t *indesc,*outdesc; char errbuf[PCAP_ERRBUF_SIZE]; char source[PCAP_BUF_SIZE]; FILE *capfile; int caplen, sync; u_int res; pcap_send_queue *squeue; struct pcap_pkthdr *pktheader; u_char *pktdata; float cpu_time; u_int npacks = 0; /* Check the validity of the command line */ if (argc <= 2 || argc >= 5) { usage(); return; } /* Retrieve the length of the capture file */ 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); /* Chek if the timestamps must be respected */ if(argc == 4 && argv[3][0] == 's') sync = TRUE; else sync = FALSE; /* Open the capture */ /* Create the source string according to the new WinPcap syntax */ if ( pcap_createsrcstr( source, // variable that will keep the source string PCAP_SRC_FILE, // we want to open a file NULL, // remote host NULL, // port on the remote host argv[1], // name of the file we want to open errbuf // error buffer ) != 0) { fprintf(stderr,"\nError creating a source string\n"); return; } /* Open the capture file */ if ( (indesc= pcap_open(source, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL) { fprintf(stderr,"\nUnable to open the file %s.\n", source); return; } /* Open the output adapter */ if ( (outdesc= pcap_open(argv[2], 100, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL) { fprintf(stderr,"\nUnable to open adapter %s.\n", source); return; } /* Check the MAC type */ 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(); } /* Allocate a send queue */ squeue = pcap_sendqueue_alloc(caplen); /* Fill the queue with the packets from the file */ 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; } npacks++; } if (res == -1) { printf("Corrupted input file.\n"); pcap_sendqueue_destroy(squeue); return; } /* Transmit the queue */ cpu_time = (float)clock (); if ((res = pcap_sendqueue_transmit(outdesc, squeue, sync)) < squeue->len) { printf("An error occurred sending the packets: %s. Only %d bytes were sent\n", pcap_geterr(outdesc), res); } cpu_time = (clock() - cpu_time)/CLK_TCK; printf ("\n\nElapsed time: %5.3f\n", cpu_time); printf ("\nTotal packets generated = %d", npacks); printf ("\nAverage packets per second = %d", (int)((double)npacks/cpu_time)); printf ("\n"); /* free the send queue */ pcap_sendqueue_destroy(squeue); /* Close the input file */ pcap_close(indesc); /* * lose the output adapter * IMPORTANT: remember to close the adapter, otherwise there will be no guarantee that all the * packets will be sent! */ pcap_close(outdesc); 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 the timestamps in the dump file. This option will work only under Windows NTx.\n\n"); exit(0); }
documentation. Copyright (c) 2002-2005 Politecnico di Torino. Copyright (c) 2005-2007 CACE Technologies. All rights reserved.