00001 /* 00002 * Copyright (c) 1999 - 2003 00003 * NetGroup, Politecnico di Torino (Italy) 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 00010 * 1. Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 2. Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * 3. Neither the name of the Politecnico di Torino nor the names of its 00016 * contributors may be used to endorse or promote products derived from 00017 * this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00020 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00021 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00022 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00023 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00024 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00025 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00026 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00027 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00029 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 * 00031 */ 00032 00033 #ifndef lint 00034 static const char rcsid[] _U_ = 00035 "@(#) $Header: /tcpdump/master/libpcap/pcap-win32.c,v 1.15.2.5 2004/06/16 15:51:32 risso Exp $ (LBL)"; 00036 #endif 00037 00038 #include <pcap-int.h> 00039 #include <packet32.h> 00040 #include <Ntddndis.h> 00041 #ifdef __MINGW32__ 00042 int* _errno(); 00043 #define errno (*_errno()) 00044 #endif /* __MINGW32__ */ 00045 00046 #ifdef HAVE_REMOTE 00047 #include <pcap-remote.h> 00048 #endif /* HAVE_REMOTE */ 00049 00050 00051 static int pcap_setfilter_win32(pcap_t *, struct bpf_program *); 00052 static int pcap_getnonblock_win32(pcap_t *, char *); 00053 static int pcap_setnonblock_win32(pcap_t *, int, char *); 00054 00055 #define PcapBufSize 256000 /*dimension of the buffer in the pcap_t structure*/ 00056 #define SIZE_BUF 1000000 00057 00058 /* 00059 * Header that the WinPcap driver associates to the packets. 00060 * Once was in bpf.h 00061 */ 00062 struct bpf_hdr { 00063 struct timeval bh_tstamp; /* time stamp */ 00064 bpf_u_int32 bh_caplen; /* length of captured portion */ 00065 bpf_u_int32 bh_datalen; /* original length of packet */ 00066 u_short bh_hdrlen; /* length of bpf header (this struct 00067 plus alignment padding) */ 00068 }; 00069 00070 /* Start winsock */ 00071 int 00072 wsockinit() 00073 { 00074 WORD wVersionRequested; 00075 WSADATA wsaData; 00076 int err; 00077 wVersionRequested = MAKEWORD( 1, 1); 00078 err = WSAStartup( wVersionRequested, &wsaData ); 00079 if ( err != 0 ) 00080 { 00081 return -1; 00082 } 00083 return 0; 00084 } 00085 00086 00087 static int 00088 pcap_stats_win32(pcap_t *p, struct pcap_stat *ps) 00089 { 00090 00091 if(PacketGetStats(p->adapter, (struct bpf_stat*)ps) != TRUE){ 00092 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "PacketGetStats error: %s", pcap_win32strerror()); 00093 return -1; 00094 } 00095 00096 return 0; 00097 } 00098 00099 static int 00100 pcap_read_win32(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 00101 { 00102 int cc; 00103 int n = 0; 00104 register u_char *bp, *ep; 00105 00106 #ifdef HAVE_REMOTE 00107 static int samp_npkt; // parameter needed for sampling, with '1 out of N' method has been requested 00108 static struct timeval samp_time; // parameter needed for sampling, with '1 every N ms' method has been requested 00109 #endif /* HAVE_REMOTE */ 00110 00111 cc = p->cc; 00112 if (p->cc == 0) { 00113 /* 00114 * Has "pcap_breakloop()" been called? 00115 */ 00116 if (p->break_loop) { 00117 /* 00118 * Yes - clear the flag that indicates that it 00119 * has, and return -2 to indicate that we were 00120 * told to break out of the loop. 00121 */ 00122 p->break_loop = 0; 00123 return (-2); 00124 } 00125 00126 /* capture the packets */ 00127 if(PacketReceivePacket(p->adapter,p->Packet,TRUE)==FALSE){ 00128 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); 00129 return (-1); 00130 } 00131 00132 cc = p->Packet->ulBytesReceived; 00133 00134 bp = p->Packet->Buffer; 00135 } 00136 else 00137 bp = p->bp; 00138 00139 /* 00140 * Loop through each packet. 00141 */ 00142 #define bhp ((struct bpf_hdr *)bp) 00143 ep = bp + cc; 00144 while (1) { 00145 register int caplen, hdrlen; 00146 00147 /* 00148 * Has "pcap_breakloop()" been called? 00149 * If so, return immediately - if we haven't read any 00150 * packets, clear the flag and return -2 to indicate 00151 * that we were told to break out of the loop, otherwise 00152 * leave the flag set, so that the *next* call will break 00153 * out of the loop without having read any packets, and 00154 * return the number of packets we've processed so far. 00155 */ 00156 if (p->break_loop) { 00157 if (n == 0) { 00158 p->break_loop = 0; 00159 return (-2); 00160 } else { 00161 p->bp = bp; 00162 p->cc = ep - bp; 00163 return (n); 00164 } 00165 } 00166 if (bp >= ep) 00167 break; 00168 00169 caplen = bhp->bh_caplen; 00170 hdrlen = bhp->bh_hdrlen; 00171 00172 #ifdef HAVE_REMOTE 00173 if (p->rmt_samp.method == PCAP_SAMP_1_EVERY_N) 00174 { 00175 samp_npkt= (samp_npkt + 1) % p->rmt_samp.value; 00176 00177 // Discard all packets that are not '1 out of N' 00178 if (samp_npkt != 0) 00179 { 00180 bp += BPF_WORDALIGN(caplen + hdrlen); 00181 continue; 00182 } 00183 } 00184 00185 if (p->rmt_samp.method == PCAP_SAMP_FIRST_AFTER_N_MS) 00186 { 00187 struct pcap_pkthdr *pkt_header= (struct pcap_pkthdr*) bp; 00188 00189 // Check if the timestamp of the arrived packet is smaller than our target time 00190 if ( (pkt_header->ts.tv_sec < samp_time.tv_sec) || 00191 ( (pkt_header->ts.tv_sec == samp_time.tv_sec) && (pkt_header->ts.tv_usec < samp_time.tv_usec) ) ) 00192 { 00193 bp += BPF_WORDALIGN(caplen + hdrlen); 00194 continue; 00195 } 00196 00197 // The arrived packet is suitable for being sent to the remote host 00198 // So, let's update the target time 00199 samp_time.tv_usec= pkt_header->ts.tv_usec + p->rmt_samp.value * 1000; 00200 if (samp_time.tv_usec > 1000000) 00201 { 00202 samp_time.tv_sec= pkt_header->ts.tv_sec + samp_time.tv_usec / 1000000; 00203 samp_time.tv_usec= samp_time.tv_usec % 1000000; 00204 } 00205 } 00206 #endif /* HAVE_REMOTE */ 00207 00208 /* 00209 * XXX A bpf_hdr matches a pcap_pkthdr. 00210 */ 00211 (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen); 00212 bp += BPF_WORDALIGN(caplen + hdrlen); 00213 if (++n >= cnt && cnt > 0) { 00214 p->bp = bp; 00215 p->cc = ep - bp; 00216 return (n); 00217 } 00218 } 00219 #undef bhp 00220 p->cc = 0; 00221 return (n); 00222 } 00223 00224 00225 static void 00226 pcap_close_win32(pcap_t *p) 00227 { 00228 if (p->buffer != NULL) 00229 free(p->buffer); 00230 if (p->adapter != NULL) { 00231 PacketCloseAdapter(p->adapter); 00232 p->adapter = NULL; 00233 } 00234 if (p->Packet) { 00235 PacketFreePacket(p->Packet); 00236 p->Packet = NULL; 00237 } 00238 } 00239 00240 pcap_t * 00241 pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, 00242 char *ebuf) 00243 { 00244 register pcap_t *p; 00245 NetType type; 00246 00247 #ifdef HAVE_REMOTE 00248 char host[PCAP_BUF_SIZE + 1]; 00249 char port[PCAP_BUF_SIZE + 1]; 00250 char name[PCAP_BUF_SIZE + 1]; 00251 int srctype; 00252 00253 /* 00254 Retrofit; we have to make older applications compatible with the remote capture 00255 So, we're calling the pcap_open_remote() from here, that is a very dirty thing. 00256 Obviously, we cannot exploit all the new features; for instance, we cannot 00257 send authentication, we cannot use a UDP data connection, and so on. 00258 */ 00259 if (pcap_parsesrcstr(device, &srctype, host, port, name, ebuf) ) 00260 return NULL; 00261 00262 if (srctype == PCAP_SRC_IFREMOTE) 00263 { 00264 p= pcap_opensource_remote(device, NULL, ebuf); 00265 00266 if (p == NULL) 00267 return NULL; 00268 00269 p->snapshot= snaplen; 00270 p->timeout= to_ms; 00271 p->rmt_flags= (promisc) ? PCAP_OPENFLAG_PROMISCUOUS : 0; 00272 00273 return p; 00274 } 00275 #endif /* HAVE_REMOTE */ 00276 00277 /* Init WinSock */ 00278 wsockinit(); 00279 00280 p = (pcap_t *)malloc(sizeof(*p)); 00281 if (p == NULL) 00282 { 00283 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); 00284 return (NULL); 00285 } 00286 memset(p, 0, sizeof(*p)); 00287 p->adapter=NULL; 00288 00289 p->adapter = PacketOpenAdapter((char*)device); 00290 00291 if (p->adapter == NULL) 00292 { 00293 /* Adapter detected but we are not able to open it. Return failure. */ 00294 snprintf(ebuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror()); 00295 return NULL; 00296 } 00297 00298 /*get network type*/ 00299 if(PacketGetNetType (p->adapter,&type) == FALSE) 00300 { 00301 snprintf(ebuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror()); 00302 goto bad; 00303 } 00304 00305 /*Set the linktype*/ 00306 switch (type.LinkType) 00307 { 00308 case NdisMediumWan: 00309 p->linktype = DLT_EN10MB; 00310 break; 00311 00312 case NdisMedium802_3: 00313 p->linktype = DLT_EN10MB; 00314 break; 00315 00316 case NdisMediumFddi: 00317 p->linktype = DLT_FDDI; 00318 break; 00319 00320 case NdisMedium802_5: 00321 p->linktype = DLT_IEEE802; 00322 break; 00323 00324 case NdisMediumArcnetRaw: 00325 p->linktype = DLT_ARCNET; 00326 break; 00327 00328 case NdisMediumArcnet878_2: 00329 p->linktype = DLT_ARCNET; 00330 break; 00331 00332 case NdisMediumAtm: 00333 p->linktype = DLT_ATM_RFC1483; 00334 break; 00335 00336 default: 00337 p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/ 00338 break; 00339 } 00340 00341 /* Set promisquous mode */ 00342 if (promisc) PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS); 00343 else PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL); 00344 00345 /* Set the buffer size */ 00346 p->bufsize = PcapBufSize; 00347 00348 p->buffer = (u_char *)malloc(PcapBufSize); 00349 if (p->buffer == NULL) 00350 { 00351 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); 00352 goto bad; 00353 } 00354 00355 p->snapshot = snaplen; 00356 00357 /* allocate Packet structure used during the capture */ 00358 if((p->Packet = PacketAllocatePacket())==NULL) 00359 { 00360 snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure"); 00361 goto bad; 00362 } 00363 00364 PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize); 00365 00366 /* allocate the standard buffer in the driver */ 00367 if(PacketSetBuff( p->adapter, SIZE_BUF)==FALSE) 00368 { 00369 snprintf(ebuf, PCAP_ERRBUF_SIZE,"driver error: not enough memory to allocate the kernel buffer\n"); 00370 goto bad; 00371 } 00372 00373 /* tell the driver to copy the buffer only if it contains at least 16K */ 00374 if(PacketSetMinToCopy(p->adapter,16000)==FALSE) 00375 { 00376 snprintf(ebuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s\n", pcap_win32strerror()); 00377 goto bad; 00378 } 00379 00380 PacketSetReadTimeout(p->adapter, to_ms); 00381 00382 p->read_op = pcap_read_win32; 00383 p->setfilter_op = pcap_setfilter_win32; 00384 p->set_datalink_op = NULL; /* can't change data link type */ 00385 p->getnonblock_op = pcap_getnonblock_win32; 00386 p->setnonblock_op = pcap_setnonblock_win32; 00387 p->stats_op = pcap_stats_win32; 00388 p->close_op = pcap_close_win32; 00389 00390 return (p); 00391 bad: 00392 if (p->adapter) 00393 PacketCloseAdapter(p->adapter); 00394 if (p->buffer != NULL) 00395 free(p->buffer); 00396 free(p); 00397 return (NULL); 00398 } 00399 00400 00401 static int 00402 pcap_setfilter_win32(pcap_t *p, struct bpf_program *fp) 00403 { 00404 if(PacketSetBpf(p->adapter,fp)==FALSE){ 00405 /* kernel filter not installed. */ 00406 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Driver error: cannot set bpf filter: %s", pcap_win32strerror()); 00407 return (-1); 00408 } 00409 return (0); 00410 } 00411 00412 00413 static int 00414 pcap_getnonblock_win32(pcap_t *p, char *errbuf) 00415 { 00416 /* 00417 * XXX - if there were a PacketGetReadTimeout() call, we 00418 * would use it, and return 1 if the timeout is -1 00419 * and 0 otherwise. 00420 */ 00421 return (p->nonblock); 00422 } 00423 00424 static int 00425 pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf) 00426 { 00427 int newtimeout; 00428 00429 if (nonblock) { 00430 /* 00431 * Set the read timeout to -1 for non-blocking mode. 00432 */ 00433 newtimeout = -1; 00434 } else { 00435 /* 00436 * Restore the timeout set when the device was opened. 00437 * (Note that this may be -1, in which case we're not 00438 * really leaving non-blocking mode.) 00439 */ 00440 newtimeout = p->timeout; 00441 } 00442 if (!PacketSetReadTimeout(p->adapter, newtimeout)) { 00443 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 00444 "PacketSetReadTimeout: %s", pcap_win32strerror()); 00445 return (-1); 00446 } 00447 p->nonblock = (newtimeout == -1); 00448 return (0); 00449 } 00450 00451 /* Set the driver working mode */ 00452 int 00453 pcap_setmode(pcap_t *p, int mode){ 00454 00455 if (p->adapter==NULL) 00456 { 00457 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "impossible to set mode while reading from a file"); 00458 return -1; 00459 } 00460 00461 if(PacketSetMode(p->adapter,mode)==FALSE) 00462 { 00463 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized"); 00464 return -1; 00465 } 00466 00467 return 0; 00468 } 00469 00470 /* Send a packet to the network */ 00471 int 00472 pcap_sendpacket(pcap_t *p, u_char *buf, int size){ 00473 LPPACKET PacketToSend; 00474 00475 if (p->adapter==NULL) 00476 { 00477 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Writing a packet is allowed only on a physical adapter"); 00478 return -1; 00479 } 00480 00481 PacketToSend=PacketAllocatePacket(); 00482 00483 if (PacketToSend == NULL) 00484 { 00485 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketAllocatePacket failed"); 00486 return -1; 00487 } 00488 00489 PacketInitPacket(PacketToSend,buf,size); 00490 if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){ 00491 PacketFreePacket(PacketToSend); 00492 return -1; 00493 } 00494 00495 PacketFreePacket(PacketToSend); 00496 return 0; 00497 } 00498 00499 /* Set the dimension of the kernel-level capture buffer */ 00500 int 00501 pcap_setbuff(pcap_t *p, int dim) 00502 { 00503 #ifdef HAVE_REMOTE 00504 if (p->rmt_clientside) 00505 { 00506 /* Currently, this is a bug: the capture buffer cannot be set with remote capture */ 00507 return 0; 00508 } 00509 #endif /* HAVE_REMOTE */ 00510 00511 if (p->adapter==NULL) 00512 { 00513 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The kernel buffer size cannot be set while reading from a file"); 00514 return -1; 00515 } 00516 00517 if(PacketSetBuff(p->adapter,dim)==FALSE) 00518 { 00519 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); 00520 return -1; 00521 } 00522 return 0; 00523 } 00524 00525 /*set the minimum amount of data that will release a read call*/ 00526 int 00527 pcap_setmintocopy(pcap_t *p, int size) 00528 { 00529 if (p->adapter==NULL) 00530 { 00531 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Impossible to set the mintocopy parameter on an offline capture"); 00532 return -1; 00533 } 00534 00535 if(PacketSetMinToCopy(p->adapter, size)==FALSE) 00536 { 00537 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size"); 00538 return -1; 00539 } 00540 return 0; 00541 }
documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.