dect
/
libpcap
Archived
13
0
Fork 0

On Win32, have pcap_setbuff, pcap_setmode, and pcap_setmintocopy ops, so

add-on capture mechanisms can supply their own code for that.
This commit is contained in:
guy 2007-10-17 18:57:34 +00:00
parent 643f12c358
commit 5cd7680c00
4 changed files with 3203 additions and 105 deletions

View File

@ -30,20 +30,73 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.18.1.1 1999-10-07 23:46:40 mcr Exp $ (LBL)
* @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.85.2.1 2007-10-17 18:57:34 guy Exp $ (LBL)
*/
#ifndef pcap_int_h
#define pcap_int_h
#include <pcap.h>
#include <pcap/pcap.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef WIN32
#include <Packet32.h>
#endif /* WIN32 */
#ifdef MSDOS
#include <fcntl.h>
#include <io.h>
#endif
#if (defined(_MSC_VER) && (_MSC_VER <= 1200)) /* we are compiling with Visual Studio 6, that doesn't support the LL suffix*/
/*
* Swap byte ordering of unsigned long long timestamp on a big endian
* machine.
*/
#define SWAPLL(ull) ((ull & 0xff00000000000000) >> 56) | \
((ull & 0x00ff000000000000) >> 40) | \
((ull & 0x0000ff0000000000) >> 24) | \
((ull & 0x000000ff00000000) >> 8) | \
((ull & 0x00000000ff000000) << 8) | \
((ull & 0x0000000000ff0000) << 24) | \
((ull & 0x000000000000ff00) << 40) | \
((ull & 0x00000000000000ff) << 56)
#else /* A recent Visual studio compiler or not VC */
/*
* Swap byte ordering of unsigned long long timestamp on a big endian
* machine.
*/
#define SWAPLL(ull) ((ull & 0xff00000000000000LL) >> 56) | \
((ull & 0x00ff000000000000LL) >> 40) | \
((ull & 0x0000ff0000000000LL) >> 24) | \
((ull & 0x000000ff00000000LL) >> 8) | \
((ull & 0x00000000ff000000LL) << 8) | \
((ull & 0x0000000000ff0000LL) << 24) | \
((ull & 0x000000000000ff00LL) << 40) | \
((ull & 0x00000000000000ffLL) << 56)
#endif /* _MSC_VER */
/*
* Savefile
*/
typedef enum {
NOT_SWAPPED,
SWAPPED,
MAYBE_SWAPPED
} swapped_type_t;
struct pcap_sf {
FILE *rfile;
int swapped;
size_t hdrsize;
swapped_type_t lengths_swapped;
int version_major;
int version_minor;
u_char *base;
@ -52,26 +105,83 @@ struct pcap_sf {
struct pcap_md {
struct pcap_stat stat;
/*XXX*/
int use_bpf;
int use_bpf; /* using kernel filter */
u_long TotPkts; /* can't oflow for 79 hrs on ether */
u_long TotAccepted; /* count accepted by filter */
u_long TotDrops; /* count of dropped packets */
long TotMissed; /* missed by i/f during this run */
long OrigMissed; /* missed by i/f before this run */
char *device; /* device name */
#ifdef linux
int pad;
int skip;
char *device;
int sock_packet; /* using Linux 2.0 compatible interface */
int timeout; /* timeout specified to pcap_open_live */
int clear_promisc; /* must clear promiscuous mode when we close */
int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */
int ifindex; /* interface index of device we're bound to */
int lo_ifindex; /* interface index of the loopback device */
struct pcap *next; /* list of open promiscuous sock_packet pcaps */
u_int packets_read; /* count of packets read with recvfrom() */
#endif
#ifdef HAVE_DAG_API
#ifdef HAVE_DAG_STREAMS_API
u_char *dag_mem_bottom; /* DAG card current memory bottom pointer */
u_char *dag_mem_top; /* DAG card current memory top pointer */
#else
void *dag_mem_base; /* DAG card memory base address */
u_int dag_mem_bottom; /* DAG card current memory bottom offset */
u_int dag_mem_top; /* DAG card current memory top offset */
#endif /* HAVE_DAG_STREAMS_API */
int dag_fcs_bits; /* Number of checksum bits from link layer */
int dag_offset_flags; /* Flags to pass to dag_offset(). */
int dag_stream; /* DAG stream number */
int dag_timeout; /* timeout specified to pcap_open_live.
* Same as in linux above, introduce
* generally? */
#endif /* HAVE_DAG_API */
};
/*
* Ultrix, DEC OSF/1^H^H^H^H^H^H^H^H^HDigital UNIX^H^H^H^H^H^H^H^H^H^H^H^H
* Tru64 UNIX, and some versions of NetBSD pad FDDI packets to make everything
* line up on a nice boundary.
*/
#ifdef __NetBSD__
#include <sys/param.h> /* needed to declare __NetBSD_Version__ */
#endif
#if defined(ultrix) || defined(__osf__) || (defined(__NetBSD__) && __NetBSD_Version__ > 106000000)
#define PCAP_FDDIPAD 3
#endif
struct pcap {
#ifdef WIN32
ADAPTER *adapter;
LPPACKET Packet;
int timeout;
int nonblock;
#else
int fd;
int selectable_fd;
int send_fd;
#endif /* WIN32 */
int snapshot;
int linktype;
int linktype; /* Network linktype */
int linktype_ext; /* Extended information stored in the linktype field of a file */
int tzoff; /* timezone offset */
int offset; /* offset for proper alignment */
int break_loop; /* flag set to force break from packet-reading loop */
#ifdef PCAP_FDDIPAD
int fddipad;
#endif
#ifdef MSDOS
int inter_packet_wait; /* offline: wait between packets */
void (*wait_proc)(void); /* call proc while waiting */
#endif
struct pcap_sf sf;
struct pcap_md md;
@ -88,13 +198,113 @@ struct pcap {
*/
u_char *pkt;
/* We're accepting only packets in this direction/these directions. */
pcap_direction_t direction;
/*
* Methods.
*/
int (*read_op)(pcap_t *, int cnt, pcap_handler, u_char *);
int (*inject_op)(pcap_t *, const void *, size_t);
int (*setfilter_op)(pcap_t *, struct bpf_program *);
int (*setdirection_op)(pcap_t *, pcap_direction_t);
int (*set_datalink_op)(pcap_t *, int);
int (*getnonblock_op)(pcap_t *, char *);
int (*setnonblock_op)(pcap_t *, int, char *);
int (*stats_op)(pcap_t *, struct pcap_stat *);
#ifdef WIN32
/*
* Win32-only; given the way the buffer size is set with BPF,
* to make this cross-platform we'll have to set the buffer
* size at open time.
*/
int (*setbuff_op)(pcap_t *, int);
/*
* These are, at least currently, specific to the Win32 NPF
* driver.
*/
int (*setmode_op)(pcap_t *, int);
int (*setmintocopy_op)(pcap_t *, int);
#endif
void (*close_op)(pcap_t *);
/*
* Placeholder for filter code if bpf not in kernel.
*/
struct bpf_program fcode;
char errbuf[PCAP_ERRBUF_SIZE];
char errbuf[PCAP_ERRBUF_SIZE + 1];
int dlt_count;
u_int *dlt_list;
struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */
};
/*
* This is a timeval as stored in a savefile.
* It has to use the same types everywhere, independent of the actual
* `struct timeval'; `struct timeval' has 32-bit tv_sec values on some
* platforms and 64-bit tv_sec values on other platforms, and writing
* out native `struct timeval' values would mean files could only be
* read on systems with the same tv_sec size as the system on which
* the file was written.
*/
struct pcap_timeval {
bpf_int32 tv_sec; /* seconds */
bpf_int32 tv_usec; /* microseconds */
};
/*
* This is a `pcap_pkthdr' as actually stored in a savefile.
*
* Do not change the format of this structure, in any way (this includes
* changes that only affect the length of fields in this structure),
* and do not make the time stamp anything other than seconds and
* microseconds (e.g., seconds and nanoseconds). Instead:
*
* introduce a new structure for the new format;
*
* send mail to "tcpdump-workers@tcpdump.org", requesting a new
* magic number for your new capture file format, and, when
* you get the new magic number, put it in "savefile.c";
*
* use that magic number for save files with the changed record
* header;
*
* make the code in "savefile.c" capable of reading files with
* the old record header as well as files with the new record header
* (using the magic number to determine the header format).
*
* Then supply the changes to "patches@tcpdump.org", so that future
* versions of libpcap and programs that use it (such as tcpdump) will
* be able to read your new capture file format.
*/
struct pcap_sf_pkthdr {
struct pcap_timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
bpf_u_int32 len; /* length this packet (off wire) */
};
/*
* How a `pcap_pkthdr' is actually stored in savefiles written
* by some patched versions of libpcap (e.g. the ones in Red
* Hat Linux 6.1 and 6.2).
*
* Do not change the format of this structure, in any way (this includes
* changes that only affect the length of fields in this structure).
* Instead, introduce a new structure, as per the above.
*/
struct pcap_sf_patched_pkthdr {
struct pcap_timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
bpf_u_int32 len; /* length this packet (off wire) */
int index;
unsigned short protocol;
unsigned char pkt_type;
};
int yylex(void);
@ -107,11 +317,63 @@ int yylex(void);
int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *);
int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *);
/* Ultrix pads to make everything line up on a nice boundary */
#if defined(ultrix) || defined(__alpha)
#define PCAP_FDDIPAD 3
#ifndef HAVE_STRLCPY
#define strlcpy(x, y, z) \
(strncpy((x), (y), (z)), \
((z) <= 0 ? 0 : ((x)[(z) - 1] = '\0')), \
strlen((y)))
#endif
#include <stdarg.h>
#if !defined(HAVE_SNPRINTF)
#define snprintf pcap_snprintf
extern int snprintf (char *, size_t, const char *, ...);
#endif
#if !defined(HAVE_VSNPRINTF)
#define vsnprintf pcap_vsnprintf
extern int vsnprintf (char *, size_t, const char *, va_list ap);
#endif
/*
* Routines that most pcap implementations can use for non-blocking mode.
*/
#if !defined(WIN32) && !defined(MSDOS)
int pcap_getnonblock_fd(pcap_t *, char *);
int pcap_setnonblock_fd(pcap_t *p, int, char *);
#endif
void pcap_close_common(pcap_t *);
/*
* Internal interfaces for "pcap_findalldevs()".
*
* "pcap_platform_finddevs()" is a platform-dependent routine to
* add devices not found by the "standard" mechanisms (SIOCGIFCONF,
* "getifaddrs()", etc..
*
* "pcap_add_if()" adds an interface to the list of interfaces.
*/
int pcap_platform_finddevs(pcap_if_t **, char *);
int add_addr_to_iflist(pcap_if_t **, const char *, u_int, struct sockaddr *,
size_t, struct sockaddr *, size_t, struct sockaddr *, size_t,
struct sockaddr *, size_t, char *);
int pcap_add_if(pcap_if_t **, const char *, u_int, const char *, char *);
struct sockaddr *dup_sockaddr(struct sockaddr *, size_t);
int add_or_find_if(pcap_if_t **, pcap_if_t **, const char *, u_int,
const char *, char *);
#ifdef WIN32
char *pcap_win32strerror(void);
#endif
int install_bpf_program(pcap_t *, struct bpf_program *);
int pcap_strcasecmp(const char *, const char *);
#ifdef __cplusplus
}
#endif
/* XXX */
extern int pcap_fddipad;
#endif

795
pcap-win32.c Normal file
View File

@ -0,0 +1,795 @@
/*
* Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
* Copyright (c) 2005 - 2007 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.
*
*/
#ifndef lint
static const char rcsid[] _U_ =
"@(#) $Header: /tcpdump/master/libpcap/pcap-win32.c,v 1.34.2.1 2007-10-17 18:57:34 guy Exp $ (LBL)";
#endif
#include <pcap-int.h>
#include <Packet32.h>
#include <Ntddndis.h>
#ifdef HAVE_DAG_API
#include <dagnew.h>
#include <dagapi.h>
#endif /* HAVE_DAG_API */
#ifdef __MINGW32__
int* _errno();
#define errno (*_errno())
#endif /* __MINGW32__ */
static int pcap_setfilter_win32_npf(pcap_t *, struct bpf_program *);
static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *);
static int pcap_getnonblock_win32(pcap_t *, char *);
static int pcap_setnonblock_win32(pcap_t *, int, char *);
#define PcapBufSize 256000 /*dimension of the buffer in the pcap_t structure*/
#define SIZE_BUF 1000000
/* Equivalent to ntohs(), but a lot faster under Windows */
#define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8)
/*
* Header that the WinPcap driver associates to the packets.
* Once was in bpf.h
*/
struct bpf_hdr {
struct timeval bh_tstamp; /* time stamp */
bpf_u_int32 bh_caplen; /* length of captured portion */
bpf_u_int32 bh_datalen; /* original length of packet */
u_short bh_hdrlen; /* length of bpf header (this struct
plus alignment padding) */
};
/* Start winsock */
int
wsockinit()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1);
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
return -1;
}
return 0;
}
static int
pcap_stats_win32(pcap_t *p, struct pcap_stat *ps)
{
if(PacketGetStats(p->adapter, (struct bpf_stat*)ps) != TRUE){
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "PacketGetStats error: %s", pcap_win32strerror());
return -1;
}
return 0;
}
/* Set the dimension of the kernel-level capture buffer */
static int
pcap_setbuff_win32(pcap_t *p, int dim)
{
if(PacketSetBuff(p->adapter,dim)==FALSE)
{
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
return -1;
}
return 0;
}
/* Set the driver working mode */
static int
pcap_setmode_win32(pcap_t *p, int mode)
{
if(PacketSetMode(p->adapter,mode)==FALSE)
{
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized");
return -1;
}
return 0;
}
/*set the minimum amount of data that will release a read call*/
static int
pcap_setmintocopy_win32(pcap_t *p, int size)
{
if(PacketSetMinToCopy(p->adapter, size)==FALSE)
{
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size");
return -1;
}
return 0;
}
static int
pcap_read_win32_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
int cc;
int n = 0;
register u_char *bp, *ep;
cc = p->cc;
if (p->cc == 0) {
/*
* Has "pcap_breakloop()" been called?
*/
if (p->break_loop) {
/*
* Yes - clear the flag that indicates that it
* has, and return -2 to indicate that we were
* told to break out of the loop.
*/
p->break_loop = 0;
return (-2);
}
/* capture the packets */
if(PacketReceivePacket(p->adapter,p->Packet,TRUE)==FALSE){
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
return (-1);
}
cc = p->Packet->ulBytesReceived;
bp = p->Packet->Buffer;
}
else
bp = p->bp;
/*
* Loop through each packet.
*/
#define bhp ((struct bpf_hdr *)bp)
ep = bp + cc;
while (1) {
register int caplen, hdrlen;
/*
* Has "pcap_breakloop()" been called?
* If so, return immediately - if we haven't read any
* packets, clear the flag and return -2 to indicate
* that we were told to break out of the loop, otherwise
* leave the flag set, so that the *next* call will break
* out of the loop without having read any packets, and
* return the number of packets we've processed so far.
*/
if (p->break_loop) {
if (n == 0) {
p->break_loop = 0;
return (-2);
} else {
p->bp = bp;
p->cc = ep - bp;
return (n);
}
}
if (bp >= ep)
break;
caplen = bhp->bh_caplen;
hdrlen = bhp->bh_hdrlen;
/*
* XXX A bpf_hdr matches a pcap_pkthdr.
*/
(*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
bp += BPF_WORDALIGN(caplen + hdrlen);
if (++n >= cnt && cnt > 0) {
p->bp = bp;
p->cc = ep - bp;
return (n);
}
}
#undef bhp
p->cc = 0;
return (n);
}
#ifdef HAVE_DAG_API
static int
pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
u_char *dp = NULL;
int packet_len = 0, caplen = 0;
struct pcap_pkthdr pcap_header;
u_char *endofbuf;
int n = 0;
dag_record_t *header;
unsigned erf_record_len;
ULONGLONG ts;
int cc;
unsigned swt;
unsigned dfp = p->adapter->DagFastProcess;
cc = p->cc;
if (cc == 0) /* Get new packets only if we have processed all the ones of the previous read */
{
/* Get new packets from the network */
if(PacketReceivePacket(p->adapter, p->Packet, TRUE)==FALSE){
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
return (-1);
}
cc = p->Packet->ulBytesReceived;
if(cc == 0)
/* The timeout has expired but we no packets arrived */
return 0;
header = (dag_record_t*)p->adapter->DagBuffer;
}
else
header = (dag_record_t*)p->bp;
endofbuf = (char*)header + cc;
/*
* Cycle through the packets
*/
do
{
erf_record_len = SWAPS(header->rlen);
if((char*)header + erf_record_len > endofbuf)
break;
/* Increase the number of captured packets */
p->md.stat.ps_recv++;
/* Find the beginning of the packet */
dp = ((u_char *)header) + dag_record_size;
/* Determine actual packet len */
switch(header->type)
{
case TYPE_ATM:
packet_len = ATM_SNAPLEN;
caplen = ATM_SNAPLEN;
dp += 4;
break;
case TYPE_ETH:
swt = SWAPS(header->wlen);
packet_len = swt - (p->md.dag_fcs_bits);
caplen = erf_record_len - dag_record_size - 2;
if (caplen > packet_len)
{
caplen = packet_len;
}
dp += 2;
break;
case TYPE_HDLC_POS:
swt = SWAPS(header->wlen);
packet_len = swt - (p->md.dag_fcs_bits);
caplen = erf_record_len - dag_record_size;
if (caplen > packet_len)
{
caplen = packet_len;
}
break;
}
if(caplen > p->snapshot)
caplen = p->snapshot;
/*
* Has "pcap_breakloop()" been called?
* If so, return immediately - if we haven't read any
* packets, clear the flag and return -2 to indicate
* that we were told to break out of the loop, otherwise
* leave the flag set, so that the *next* call will break
* out of the loop without having read any packets, and
* return the number of packets we've processed so far.
*/
if (p->break_loop)
{
if (n == 0)
{
p->break_loop = 0;
return (-2);
}
else
{
p->bp = (char*)header;
p->cc = endofbuf - (char*)header;
return (n);
}
}
if(!dfp)
{
/* convert between timestamp formats */
ts = header->ts;
pcap_header.ts.tv_sec = (int)(ts >> 32);
ts = (ts & 0xffffffffi64) * 1000000;
ts += 0x80000000; /* rounding */
pcap_header.ts.tv_usec = (int)(ts >> 32);
if (pcap_header.ts.tv_usec >= 1000000) {
pcap_header.ts.tv_usec -= 1000000;
pcap_header.ts.tv_sec++;
}
}
/* No underlaying filtering system. We need to filter on our own */
if (p->fcode.bf_insns)
{
if (bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0)
{
/* Move to next packet */
header = (dag_record_t*)((char*)header + erf_record_len);
continue;
}
}
/* Fill the header for the user suppplied callback function */
pcap_header.caplen = caplen;
pcap_header.len = packet_len;
/* Call the callback function */
(*callback)(user, &pcap_header, dp);
/* Move to next packet */
header = (dag_record_t*)((char*)header + erf_record_len);
/* Stop if the number of packets requested by user has been reached*/
if (++n >= cnt && cnt > 0)
{
p->bp = (char*)header;
p->cc = endofbuf - (char*)header;
return (n);
}
}
while((u_char*)header < endofbuf);
return 1;
}
#endif /* HAVE_DAG_API */
/* Send a packet to the network */
static int
pcap_inject_win32(pcap_t *p, const void *buf, size_t size){
LPPACKET PacketToSend;
PacketToSend=PacketAllocatePacket();
if (PacketToSend == NULL)
{
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketAllocatePacket failed");
return -1;
}
PacketInitPacket(PacketToSend,(PVOID)buf,size);
if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed");
PacketFreePacket(PacketToSend);
return -1;
}
PacketFreePacket(PacketToSend);
/*
* We assume it all got sent if "PacketSendPacket()" succeeded.
* "pcap_inject()" is expected to return the number of bytes
* sent.
*/
return size;
}
static void
pcap_close_win32(pcap_t *p)
{
pcap_close_common(p);
if (p->adapter != NULL) {
PacketCloseAdapter(p->adapter);
p->adapter = NULL;
}
if (p->Packet) {
PacketFreePacket(p->Packet);
p->Packet = NULL;
}
}
pcap_t *
pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
char *ebuf)
{
register pcap_t *p;
NetType type;
/* Init WinSock */
wsockinit();
p = (pcap_t *)malloc(sizeof(*p));
if (p == NULL)
{
snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return (NULL);
}
memset(p, 0, sizeof(*p));
p->adapter=NULL;
p->adapter = PacketOpenAdapter((char*)device);
if (p->adapter == NULL)
{
free(p);
/* Adapter detected but we are not able to open it. Return failure. */
snprintf(ebuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror());
return NULL;
}
/*get network type*/
if(PacketGetNetType (p->adapter,&type) == FALSE)
{
snprintf(ebuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror());
goto bad;
}
/*Set the linktype*/
switch (type.LinkType)
{
case NdisMediumWan:
p->linktype = DLT_EN10MB;
break;
case NdisMedium802_3:
p->linktype = DLT_EN10MB;
/*
* This is (presumably) a real Ethernet capture; give it a
* link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
* that an application can let you choose it, in case you're
* capturing DOCSIS traffic that a Cisco Cable Modem
* Termination System is putting out onto an Ethernet (it
* doesn't put an Ethernet header onto the wire, it puts raw
* DOCSIS frames out on the wire inside the low-level
* Ethernet framing).
*/
p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
/*
* If that fails, just leave the list empty.
*/
if (p->dlt_list != NULL) {
p->dlt_list[0] = DLT_EN10MB;
p->dlt_list[1] = DLT_DOCSIS;
p->dlt_count = 2;
}
break;
case NdisMediumFddi:
p->linktype = DLT_FDDI;
break;
case NdisMedium802_5:
p->linktype = DLT_IEEE802;
break;
case NdisMediumArcnetRaw:
p->linktype = DLT_ARCNET;
break;
case NdisMediumArcnet878_2:
p->linktype = DLT_ARCNET;
break;
case NdisMediumAtm:
p->linktype = DLT_ATM_RFC1483;
break;
case NdisMediumCHDLC:
p->linktype = DLT_CHDLC;
break;
case NdisMediumPPPSerial:
p->linktype = DLT_PPP_SERIAL;
break;
case NdisMediumNull:
p->linktype = DLT_NULL;
break;
case NdisMediumBare80211:
p->linktype = DLT_IEEE802_11;
break;
case NdisMediumRadio80211:
p->linktype = DLT_IEEE802_11_RADIO;
break;
case NdisMediumPpi:
p->linktype = DLT_PPI;
break;
default:
p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/
break;
}
/* Set promiscuous mode */
if (promisc)
{
if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE)
{
snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode");
goto bad;
}
}
else
{
if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL) == FALSE)
{
snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode");
goto bad;
}
}
/* Set the buffer size */
p->bufsize = PcapBufSize;
/* Store the timeout. Used by pcap_setnonblock() */
p->timeout= to_ms;
/* allocate Packet structure used during the capture */
if((p->Packet = PacketAllocatePacket())==NULL)
{
snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure");
goto bad;
}
if(!(p->adapter->Flags & INFO_FLAG_DAG_CARD))
{
/*
* Traditional Adapter
*/
p->buffer = (u_char *)malloc(PcapBufSize);
if (p->buffer == NULL)
{
snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
goto bad;
}
PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize);
p->snapshot = snaplen;
/* allocate the standard buffer in the driver */
if(PacketSetBuff( p->adapter, SIZE_BUF)==FALSE)
{
snprintf(ebuf, PCAP_ERRBUF_SIZE,"driver error: not enough memory to allocate the kernel buffer\n");
goto bad;
}
/* tell the driver to copy the buffer only if it contains at least 16K */
if(PacketSetMinToCopy(p->adapter,16000)==FALSE)
{
snprintf(ebuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s\n", pcap_win32strerror());
goto bad;
}
}
else
#ifdef HAVE_DAG_API
{
/*
* Dag Card
*/
LONG status;
HKEY dagkey;
DWORD lptype;
DWORD lpcbdata;
int postype = 0;
char keyname[512];
snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s",
"SYSTEM\\CurrentControlSet\\Services\\DAG",
strstr(_strlwr((char*)device), "dag"));
do
{
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &dagkey);
if(status != ERROR_SUCCESS)
break;
status = RegQueryValueEx(dagkey,
"PosType",
NULL,
&lptype,
(char*)&postype,
&lpcbdata);
if(status != ERROR_SUCCESS)
{
postype = 0;
}
RegCloseKey(dagkey);
}
while(FALSE);
p->snapshot = PacketSetSnapLen(p->adapter, snaplen);
/* Set the length of the FCS associated to any packet. This value
* will be subtracted to the packet length */
p->md.dag_fcs_bits = p->adapter->DagFcsLen;
}
#else
goto bad;
#endif /* HAVE_DAG_API */
PacketSetReadTimeout(p->adapter, to_ms);
#ifdef HAVE_DAG_API
if(p->adapter->Flags & INFO_FLAG_DAG_CARD)
{
/* install dag specific handlers for read and setfilter */
p->read_op = pcap_read_win32_dag;
p->setfilter_op = pcap_setfilter_win32_dag;
}
else
{
#endif /* HAVE_DAG_API */
/* install traditional npf handlers for read and setfilter */
p->read_op = pcap_read_win32_npf;
p->setfilter_op = pcap_setfilter_win32_npf;
#ifdef HAVE_DAG_API
}
#endif /* HAVE_DAG_API */
p->setdirection_op = NULL; /* Not implemented. */
/* XXX - can this be implemented on some versions of Windows? */
p->inject_op = pcap_inject_win32;
p->set_datalink_op = NULL; /* can't change data link type */
p->getnonblock_op = pcap_getnonblock_win32;
p->setnonblock_op = pcap_setnonblock_win32;
p->stats_op = pcap_stats_win32;
p->setbuff_op = pcap_setbuff_win32;
p->setmode_op = pcap_setmode_win32;
p->setmintocopy_op = pcap_setmintocopy_win32;
p->close_op = pcap_close_win32;
return (p);
bad:
if (p->adapter)
PacketCloseAdapter(p->adapter);
if (p->buffer != NULL)
free(p->buffer);
if(p->Packet)
PacketFreePacket(p->Packet);
/*
* Get rid of any link-layer type list we allocated.
*/
if (p->dlt_list != NULL)
free(p->dlt_list);
free(p);
return (NULL);
}
static int
pcap_setfilter_win32_npf(pcap_t *p, struct bpf_program *fp)
{
if(PacketSetBpf(p->adapter,fp)==FALSE){
/*
* Kernel filter not installed.
* XXX - fall back on userland filtering, as is done
* on other platforms?
*/
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Driver error: cannot set bpf filter: %s", pcap_win32strerror());
return (-1);
}
/*
* Discard any previously-received packets, as they might have
* passed whatever filter was formerly in effect, but might
* not pass this filter (BIOCSETF discards packets buffered
* in the kernel, so you can lose packets in any case).
*/
p->cc = 0;
return (0);
}
/*
* We filter at user level, since the kernel driver does't process the packets
*/
static int
pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) {
if(!fp)
{
strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf));
return -1;
}
/* Install a user level filter */
if (install_bpf_program(p, fp) < 0)
{
snprintf(p->errbuf, sizeof(p->errbuf),
"setfilter, unable to install the filter: %s", pcap_strerror(errno));
return -1;
}
p->md.use_bpf = 0;
return (0);
}
static int
pcap_getnonblock_win32(pcap_t *p, char *errbuf)
{
/*
* XXX - if there were a PacketGetReadTimeout() call, we
* would use it, and return 1 if the timeout is -1
* and 0 otherwise.
*/
return (p->nonblock);
}
static int
pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf)
{
int newtimeout;
if (nonblock) {
/*
* Set the read timeout to -1 for non-blocking mode.
*/
newtimeout = -1;
} else {
/*
* Restore the timeout set when the device was opened.
* (Note that this may be -1, in which case we're not
* really leaving non-blocking mode.)
*/
newtimeout = p->timeout;
}
if (!PacketSetReadTimeout(p->adapter, newtimeout)) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"PacketSetReadTimeout: %s", pcap_win32strerror());
return (-1);
}
p->nonblock = (newtimeout == -1);
return (0);
}
/*platform-dependent routine to add devices other than NDIS interfaces*/
int
pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
{
return (0);
}

833
pcap.c
View File

@ -32,31 +32,59 @@
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.29.1.1 1999-10-07 23:46:40 mcr Exp $ (LBL)";
static const char rcsid[] _U_ =
"@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.112.2.1 2007-10-17 18:57:34 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include <pcap-stdinc.h>
#else /* WIN32 */
#include <sys/types.h>
#endif /* WIN32 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(_MSC_VER) && !defined(__BORLANDC__)
#include <unistd.h>
#endif
#include <fcntl.h>
#include <errno.h>
#include "gnuc.h"
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
#ifdef MSDOS
#include "pcap-dos.h"
#endif
#include "pcap-int.h"
#ifdef HAVE_DAG_API
#include <dagnew.h>
#include <dagapi.h>
#endif
int
pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
if (p->sf.rfile != NULL)
return (pcap_offline_read(p, cnt, callback, user));
return (pcap_read(p, cnt, callback, user));
return p->read_op(p, cnt, callback, user);
}
/*
* XXX - is this necessary?
*/
int
pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
return p->read_op(p, cnt, callback, user);
}
int
@ -65,15 +93,18 @@ pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
register int n;
for (;;) {
if (p->sf.rfile != NULL)
if (p->sf.rfile != NULL) {
/*
* 0 means EOF, so don't loop if we get 0.
*/
n = pcap_offline_read(p, cnt, callback, user);
else {
} else {
/*
* XXX keep reading until we get something
* (or an error occurs)
*/
do {
n = pcap_read(p, cnt, callback, user);
n = p->read_op(p, cnt, callback, user);
} while (n == 0);
}
if (n <= 0)
@ -111,12 +142,399 @@ pcap_next(pcap_t *p, struct pcap_pkthdr *h)
return (s.pkt);
}
struct pkt_for_fakecallback {
struct pcap_pkthdr *hdr;
const u_char **pkt;
};
static void
pcap_fakecallback(u_char *userData, const struct pcap_pkthdr *h,
const u_char *pkt)
{
struct pkt_for_fakecallback *sp = (struct pkt_for_fakecallback *)userData;
*sp->hdr = *h;
*sp->pkt = pkt;
}
int
pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header,
const u_char **pkt_data)
{
struct pkt_for_fakecallback s;
s.hdr = &p->pcap_header;
s.pkt = pkt_data;
/* Saves a pointer to the packet headers */
*pkt_header= &p->pcap_header;
if (p->sf.rfile != NULL) {
int status;
/* We are on an offline capture */
status = pcap_offline_read(p, 1, pcap_fakecallback,
(u_char *)&s);
/*
* Return codes for pcap_offline_read() are:
* - 0: EOF
* - -1: error
* - >1: OK
* The first one ('0') conflicts with the return code of
* 0 from pcap_read() meaning "no packets arrived before
* the timeout expired", so we map it to -2 so you can
* distinguish between an EOF from a savefile and a
* "no packets arrived before the timeout expired, try
* again" from a live capture.
*/
if (status == 0)
return (-2);
else
return (status);
}
/*
* Return codes for pcap_read() are:
* - 0: timeout
* - -1: error
* - -2: loop was broken out of with pcap_breakloop()
* - >1: OK
* The first one ('0') conflicts with the return code of 0 from
* pcap_offline_read() meaning "end of file".
*/
return (p->read_op(p, 1, pcap_fakecallback, (u_char *)&s));
}
/*
* Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate.
*/
void
pcap_breakloop(pcap_t *p)
{
p->break_loop = 1;
}
int
pcap_datalink(pcap_t *p)
{
return (p->linktype);
}
int
pcap_datalink_ext(pcap_t *p)
{
return (p->linktype_ext);
}
int
pcap_list_datalinks(pcap_t *p, int **dlt_buffer)
{
if (p->dlt_count == 0) {
/*
* We couldn't fetch the list of DLTs, which means
* this platform doesn't support changing the
* DLT for an interface. Return a list of DLTs
* containing only the DLT this device supports.
*/
*dlt_buffer = (int*)malloc(sizeof(**dlt_buffer));
if (*dlt_buffer == NULL) {
(void)snprintf(p->errbuf, sizeof(p->errbuf),
"malloc: %s", pcap_strerror(errno));
return (-1);
}
**dlt_buffer = p->linktype;
return (1);
} else {
*dlt_buffer = (int*)calloc(sizeof(**dlt_buffer), p->dlt_count);
if (*dlt_buffer == NULL) {
(void)snprintf(p->errbuf, sizeof(p->errbuf),
"malloc: %s", pcap_strerror(errno));
return (-1);
}
(void)memcpy(*dlt_buffer, p->dlt_list,
sizeof(**dlt_buffer) * p->dlt_count);
return (p->dlt_count);
}
}
int
pcap_set_datalink(pcap_t *p, int dlt)
{
int i;
const char *dlt_name;
if (p->dlt_count == 0 || p->set_datalink_op == NULL) {
/*
* We couldn't fetch the list of DLTs, or we don't
* have a "set datalink" operation, which means
* this platform doesn't support changing the
* DLT for an interface. Check whether the new
* DLT is the one this interface supports.
*/
if (p->linktype != dlt)
goto unsupported;
/*
* It is, so there's nothing we need to do here.
*/
return (0);
}
for (i = 0; i < p->dlt_count; i++)
if (p->dlt_list[i] == dlt)
break;
if (i >= p->dlt_count)
goto unsupported;
if (p->dlt_count == 2 && p->dlt_list[0] == DLT_EN10MB &&
dlt == DLT_DOCSIS) {
/*
* This is presumably an Ethernet device, as the first
* link-layer type it offers is DLT_EN10MB, and the only
* other type it offers is DLT_DOCSIS. That means that
* we can't tell the driver to supply DOCSIS link-layer
* headers - we're just pretending that's what we're
* getting, as, presumably, we're capturing on a dedicated
* link to a Cisco Cable Modem Termination System, and
* it's putting raw DOCSIS frames on the wire inside low-level
* Ethernet framing.
*/
p->linktype = dlt;
return (0);
}
if (p->set_datalink_op(p, dlt) == -1)
return (-1);
p->linktype = dlt;
return (0);
unsupported:
dlt_name = pcap_datalink_val_to_name(dlt);
if (dlt_name != NULL) {
(void) snprintf(p->errbuf, sizeof(p->errbuf),
"%s is not one of the DLTs supported by this device",
dlt_name);
} else {
(void) snprintf(p->errbuf, sizeof(p->errbuf),
"DLT %d is not one of the DLTs supported by this device",
dlt);
}
return (-1);
}
struct dlt_choice {
const char *name;
const char *description;
int dlt;
};
#define DLT_CHOICE(code, description) { #code, description, code }
#define DLT_CHOICE_SENTINEL { NULL, NULL, 0 }
static struct dlt_choice dlt_choices[] = {
DLT_CHOICE(DLT_NULL, "BSD loopback"),
DLT_CHOICE(DLT_EN10MB, "Ethernet"),
DLT_CHOICE(DLT_IEEE802, "Token ring"),
DLT_CHOICE(DLT_ARCNET, "BSD ARCNET"),
DLT_CHOICE(DLT_SLIP, "SLIP"),
DLT_CHOICE(DLT_PPP, "PPP"),
DLT_CHOICE(DLT_FDDI, "FDDI"),
DLT_CHOICE(DLT_ATM_RFC1483, "RFC 1483 LLC-encapsulated ATM"),
DLT_CHOICE(DLT_RAW, "Raw IP"),
DLT_CHOICE(DLT_SLIP_BSDOS, "BSD/OS SLIP"),
DLT_CHOICE(DLT_PPP_BSDOS, "BSD/OS PPP"),
DLT_CHOICE(DLT_ATM_CLIP, "Linux Classical IP-over-ATM"),
DLT_CHOICE(DLT_PPP_SERIAL, "PPP over serial"),
DLT_CHOICE(DLT_PPP_ETHER, "PPPoE"),
DLT_CHOICE(DLT_SYMANTEC_FIREWALL, "Symantec Firewall"),
DLT_CHOICE(DLT_C_HDLC, "Cisco HDLC"),
DLT_CHOICE(DLT_IEEE802_11, "802.11"),
DLT_CHOICE(DLT_FRELAY, "Frame Relay"),
DLT_CHOICE(DLT_LOOP, "OpenBSD loopback"),
DLT_CHOICE(DLT_ENC, "OpenBSD encapsulated IP"),
DLT_CHOICE(DLT_LINUX_SLL, "Linux cooked"),
DLT_CHOICE(DLT_LTALK, "Localtalk"),
DLT_CHOICE(DLT_PFLOG, "OpenBSD pflog file"),
DLT_CHOICE(DLT_PRISM_HEADER, "802.11 plus Prism header"),
DLT_CHOICE(DLT_IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"),
DLT_CHOICE(DLT_SUNATM, "Sun raw ATM"),
DLT_CHOICE(DLT_IEEE802_11_RADIO, "802.11 plus radiotap header"),
DLT_CHOICE(DLT_ARCNET_LINUX, "Linux ARCNET"),
DLT_CHOICE(DLT_JUNIPER_MLPPP, "Juniper Multi-Link PPP"),
DLT_CHOICE(DLT_JUNIPER_MLFR, "Juniper Multi-Link Frame Relay"),
DLT_CHOICE(DLT_JUNIPER_ES, "Juniper Encryption Services PIC"),
DLT_CHOICE(DLT_JUNIPER_GGSN, "Juniper GGSN PIC"),
DLT_CHOICE(DLT_JUNIPER_MFR, "Juniper FRF.16 Frame Relay"),
DLT_CHOICE(DLT_JUNIPER_ATM2, "Juniper ATM2 PIC"),
DLT_CHOICE(DLT_JUNIPER_SERVICES, "Juniper Advanced Services PIC"),
DLT_CHOICE(DLT_JUNIPER_ATM1, "Juniper ATM1 PIC"),
DLT_CHOICE(DLT_APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"),
DLT_CHOICE(DLT_MTP2_WITH_PHDR, "SS7 MTP2 with Pseudo-header"),
DLT_CHOICE(DLT_MTP2, "SS7 MTP2"),
DLT_CHOICE(DLT_MTP3, "SS7 MTP3"),
DLT_CHOICE(DLT_SCCP, "SS7 SCCP"),
DLT_CHOICE(DLT_DOCSIS, "DOCSIS"),
DLT_CHOICE(DLT_LINUX_IRDA, "Linux IrDA"),
DLT_CHOICE(DLT_IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"),
DLT_CHOICE(DLT_JUNIPER_MONITOR, "Juniper Passive Monitor PIC"),
DLT_CHOICE(DLT_PPP_PPPD, "PPP for pppd, with direction flag"),
DLT_CHOICE(DLT_JUNIPER_PPPOE, "Juniper PPPoE"),
DLT_CHOICE(DLT_JUNIPER_PPPOE_ATM, "Juniper PPPoE/ATM"),
DLT_CHOICE(DLT_GPRS_LLC, "GPRS LLC"),
DLT_CHOICE(DLT_GPF_T, "GPF-T"),
DLT_CHOICE(DLT_GPF_F, "GPF-F"),
DLT_CHOICE(DLT_JUNIPER_PIC_PEER, "Juniper PIC Peer"),
DLT_CHOICE(DLT_ERF_ETH, "Ethernet with Endace ERF header"),
DLT_CHOICE(DLT_ERF_POS, "Packet-over-SONET with Endace ERF header"),
DLT_CHOICE(DLT_LINUX_LAPD, "Linux vISDN LAPD"),
DLT_CHOICE(DLT_JUNIPER_ETHER, "Juniper Ethernet"),
DLT_CHOICE(DLT_JUNIPER_PPP, "Juniper PPP"),
DLT_CHOICE(DLT_JUNIPER_FRELAY, "Juniper Frame Relay"),
DLT_CHOICE(DLT_JUNIPER_CHDLC, "Juniper C-HDLC"),
DLT_CHOICE(DLT_MFR, "FRF.16 Frame Relay"),
DLT_CHOICE(DLT_JUNIPER_VP, "Juniper Voice PIC"),
DLT_CHOICE(DLT_A429, "Arinc 429"),
DLT_CHOICE(DLT_A653_ICM, "Arinc 653 Interpartition Communication"),
DLT_CHOICE(DLT_USB, "USB"),
DLT_CHOICE(DLT_BLUETOOTH_HCI_H4, "Bluetooth HCI UART transport layer"),
DLT_CHOICE(DLT_IEEE802_16_MAC_CPS, "IEEE 802.16 MAC Common Part Sublayer"),
DLT_CHOICE(DLT_USB_LINUX, "USB with Linux header"),
DLT_CHOICE(DLT_CAN20B, "Controller Area Network (CAN) v. 2.0B"),
DLT_CHOICE(DLT_IEEE802_15_4_LINUX, "IEEE 802.15.4 with Linux padding"),
DLT_CHOICE(DLT_PPI, "Per-Packet Information"),
DLT_CHOICE(DLT_IEEE802_16_MAC_CPS_RADIO, "IEEE 802.16 MAC Common Part Sublayer plus radiotap header"),
DLT_CHOICE(DLT_JUNIPER_ISM, "Juniper Integrated Service Module"),
DLT_CHOICE(DLT_IEEE802_15_4, "IEEE 802.15.4"),
DLT_CHOICE(DLT_SITA, "SITA pseudo-header"),
DLT_CHOICE(DLT_ERF, "Endace ERF header"),
DLT_CHOICE(DLT_RAIF1, "Ethernet with u10 Networks pseudo-header"),
DLT_CHOICE(DLT_IPMB, "IPMB"),
DLT_CHOICE(DLT_JUNIPER_ST, "Juniper Secure Tunnel"),
DLT_CHOICE(DLT_BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"),
DLT_CHOICE(DLT_AX25_KISS, "AX.25 with KISS header"),
DLT_CHOICE_SENTINEL
};
/*
* This array is designed for mapping upper and lower case letter
* together for a case independent comparison. The mappings are
* based upon ascii character sequences.
*/
static const u_char charmap[] = {
(u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003',
(u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007',
(u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013',
(u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017',
(u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023',
(u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027',
(u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033',
(u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037',
(u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043',
(u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047',
(u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053',
(u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057',
(u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063',
(u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067',
(u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073',
(u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077',
(u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143',
(u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
(u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
(u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
(u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
(u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
(u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133',
(u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137',
(u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143',
(u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
(u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
(u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
(u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
(u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
(u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173',
(u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177',
(u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203',
(u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207',
(u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213',
(u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217',
(u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223',
(u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227',
(u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233',
(u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237',
(u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243',
(u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247',
(u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253',
(u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257',
(u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263',
(u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267',
(u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273',
(u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277',
(u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343',
(u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
(u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
(u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
(u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
(u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
(u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333',
(u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337',
(u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343',
(u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
(u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
(u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
(u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
(u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
(u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373',
(u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377',
};
int
pcap_strcasecmp(const char *s1, const char *s2)
{
register const u_char *cm = charmap,
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
while (cm[*us1] == cm[*us2++])
if (*us1++ == '\0')
return(0);
return (cm[*us1] - cm[*--us2]);
}
int
pcap_datalink_name_to_val(const char *name)
{
int i;
for (i = 0; dlt_choices[i].name != NULL; i++) {
if (pcap_strcasecmp(dlt_choices[i].name + sizeof("DLT_") - 1,
name) == 0)
return (dlt_choices[i].dlt);
}
return (-1);
}
const char *
pcap_datalink_val_to_name(int dlt)
{
int i;
for (i = 0; dlt_choices[i].name != NULL; i++) {
if (dlt_choices[i].dlt == dlt)
return (dlt_choices[i].name + sizeof("DLT_") - 1);
}
return (NULL);
}
const char *
pcap_datalink_val_to_description(int dlt)
{
int i;
for (i = 0; dlt_choices[i].name != NULL; i++) {
if (dlt_choices[i].dlt == dlt)
return (dlt_choices[i].description);
}
return (NULL);
}
int
pcap_snapshot(pcap_t *p)
{
@ -150,9 +568,24 @@ pcap_file(pcap_t *p)
int
pcap_fileno(pcap_t *p)
{
#ifndef WIN32
return (p->fd);
#else
if (p->adapter != NULL)
return ((int)(DWORD)p->adapter->hFile);
else
return (-1);
#endif
}
#if !defined(WIN32) && !defined(MSDOS)
int
pcap_get_selectable_fd(pcap_t *p)
{
return (p->selectable_fd);
}
#endif
void
pcap_perror(pcap_t *p, char *prefix)
{
@ -165,10 +598,112 @@ pcap_geterr(pcap_t *p)
return (p->errbuf);
}
int
pcap_getnonblock(pcap_t *p, char *errbuf)
{
return p->getnonblock_op(p, errbuf);
}
/*
* Get the current non-blocking mode setting, under the assumption that
* it's just the standard POSIX non-blocking flag.
*
* We don't look at "p->nonblock", in case somebody tweaked the FD
* directly.
*/
#if !defined(WIN32) && !defined(MSDOS)
int
pcap_getnonblock_fd(pcap_t *p, char *errbuf)
{
int fdflags;
fdflags = fcntl(p->fd, F_GETFL, 0);
if (fdflags == -1) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
pcap_strerror(errno));
return (-1);
}
if (fdflags & O_NONBLOCK)
return (1);
else
return (0);
}
#endif
int
pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
{
return p->setnonblock_op(p, nonblock, errbuf);
}
#if !defined(WIN32) && !defined(MSDOS)
/*
* Set non-blocking mode, under the assumption that it's just the
* standard POSIX non-blocking flag. (This can be called by the
* per-platform non-blocking-mode routine if that routine also
* needs to do some additional work.)
*/
int
pcap_setnonblock_fd(pcap_t *p, int nonblock, char *errbuf)
{
int fdflags;
fdflags = fcntl(p->fd, F_GETFL, 0);
if (fdflags == -1) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_GETFL: %s",
pcap_strerror(errno));
return (-1);
}
if (nonblock)
fdflags |= O_NONBLOCK;
else
fdflags &= ~O_NONBLOCK;
if (fcntl(p->fd, F_SETFL, fdflags) == -1) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "F_SETFL: %s",
pcap_strerror(errno));
return (-1);
}
return (0);
}
#endif
#ifdef WIN32
/*
* Generate a string for the last Win32-specific error (i.e. an error generated when
* calling a Win32 API).
* For errors occurred during standard C calls, we still use pcap_strerror()
*/
char *
pcap_win32strerror(void)
{
DWORD error;
static char errbuf[PCAP_ERRBUF_SIZE+1];
int errlen;
char *p;
error = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
PCAP_ERRBUF_SIZE, NULL);
/*
* "FormatMessage()" "helpfully" sticks CR/LF at the end of the
* message. Get rid of it.
*/
errlen = strlen(errbuf);
if (errlen >= 2) {
errbuf[errlen - 1] = '\0';
errbuf[errlen - 2] = '\0';
}
p = strchr(errbuf, '\0');
snprintf (p, sizeof(errbuf)-(p-errbuf), " (%lu)", error);
return (errbuf);
}
#endif
/*
* Not all systems have strerror().
*/
char *
const char *
pcap_strerror(int errnum)
{
#ifdef HAVE_STRERROR
@ -180,27 +715,275 @@ pcap_strerror(int errnum)
if ((unsigned int)errnum < sys_nerr)
return ((char *)sys_errlist[errnum]);
(void)sprintf(ebuf, "Unknown error: %d", errnum);
(void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
return(ebuf);
#endif
}
int
pcap_setfilter(pcap_t *p, struct bpf_program *fp)
{
return p->setfilter_op(p, fp);
}
/*
* Set direction flag, which controls whether we accept only incoming
* packets, only outgoing packets, or both.
* Note that, depending on the platform, some or all direction arguments
* might not be supported.
*/
int
pcap_setdirection(pcap_t *p, pcap_direction_t d)
{
if (p->setdirection_op == NULL) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Setting direction is not implemented on this platform");
return -1;
} else
return p->setdirection_op(p, d);
}
int
pcap_stats(pcap_t *p, struct pcap_stat *ps)
{
return p->stats_op(p, ps);
}
static int
pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_)
{
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Statistics aren't available from a pcap_open_dead pcap_t");
return (-1);
}
#ifdef WIN32
int
pcap_setbuff(pcap_t *p, int dim)
{
return p->setbuff_op(p, dim);
}
static int
pcap_setbuff_dead(pcap_t *p, int dim)
{
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The kernel buffer size cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
int
pcap_setmode(pcap_t *p, int mode)
{
return p->setmode_op(p, mode);
}
static int
pcap_setmode_dead(pcap_t *p, int mode)
{
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"impossible to set mode on a pcap_open_dead pcap_t");
return (-1);
}
int
pcap_setmintocopy(pcap_t *p, int size)
{
return p->setintocopy_op(p, size);
}
static int
pcap_setmintocopy_dead(pcap_t *p, int size)
{
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"The mintocopy parameter cannot be set on a pcap_open_dead pcap_t");
return (-1);
}
#endif
void
pcap_close_common(pcap_t *p)
{
if (p->buffer != NULL)
free(p->buffer);
#if !defined(WIN32) && !defined(MSDOS)
if (p->fd >= 0)
close(p->fd);
#endif
}
static void
pcap_close_dead(pcap_t *p _U_)
{
/* Nothing to do. */
}
pcap_t *
pcap_open_dead(int linktype, int snaplen)
{
pcap_t *p;
p = malloc(sizeof(*p));
if (p == NULL)
return NULL;
memset (p, 0, sizeof(*p));
p->snapshot = snaplen;
p->linktype = linktype;
p->stats_op = pcap_stats_dead;
#ifdef WIN32
p->setbuff_op = pcap_setbuff_dead;
p->setmode_op = pcap_setmode_dead;
p->setmintocopy_op = pcap_setmintocopy_dead;
#endif
p->close_op = pcap_close_dead;
return p;
}
/*
* API compatible with WinPcap's "send a packet" routine - returns -1
* on error, 0 otherwise.
*
* XXX - what if we get a short write?
*/
int
pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
{
if (p->inject_op(p, buf, size) == -1)
return (-1);
return (0);
}
/*
* API compatible with OpenBSD's "send a packet" routine - returns -1 on
* error, number of bytes written otherwise.
*/
int
pcap_inject(pcap_t *p, const void *buf, size_t size)
{
return (p->inject_op(p, buf, size));
}
void
pcap_close(pcap_t *p)
{
/*XXX*/
if (p->fd >= 0)
close(p->fd);
if (p->sf.rfile != NULL) {
(void)fclose(p->sf.rfile);
if (p->sf.base != NULL)
free(p->sf.base);
} else if (p->buffer != NULL)
free(p->buffer);
#ifdef linux
if (p->md.device != NULL)
free(p->md.device);
#endif
p->close_op(p);
if (p->dlt_list != NULL)
free(p->dlt_list);
pcap_freecode(&p->fcode);
free(p);
}
/*
* We make the version string static, and return a pointer to it, rather
* than exporting the version string directly. On at least some UNIXes,
* if you import data from a shared library into an program, the data is
* bound into the program binary, so if the string in the version of the
* library with which the program was linked isn't the same as the
* string in the version of the library with which the program is being
* run, various undesirable things may happen (warnings, the string
* being the one from the version of the library with which the program
* was linked, or even weirder things, such as the string being the one
* from the library but being truncated).
*/
#ifdef HAVE_VERSION_H
#include "version.h"
#else
static const char pcap_version_string[] = "libpcap version 0.9[.x]";
#endif
#ifdef WIN32
/*
* XXX - it'd be nice if we could somehow generate the WinPcap and libpcap
* version numbers when building WinPcap. (It'd be nice to do so for
* the packet.dll version number as well.)
*/
static const char wpcap_version_string[] = "4.0";
static const char pcap_version_string_fmt[] =
"WinPcap version %s, based on %s";
static const char pcap_version_string_packet_dll_fmt[] =
"WinPcap version %s (packet.dll version %s), based on %s";
static char *full_pcap_version_string;
const char *
pcap_lib_version(void)
{
char *packet_version_string;
size_t full_pcap_version_string_len;
if (full_pcap_version_string == NULL) {
/*
* Generate the version string.
*/
packet_version_string = PacketGetVersion();
if (strcmp(wpcap_version_string, packet_version_string) == 0) {
/*
* WinPcap version string and packet.dll version
* string are the same; just report the WinPcap
* version.
*/
full_pcap_version_string_len =
(sizeof pcap_version_string_fmt - 4) +
strlen(wpcap_version_string) +
strlen(pcap_version_string);
full_pcap_version_string =
malloc(full_pcap_version_string_len);
sprintf(full_pcap_version_string,
pcap_version_string_fmt, wpcap_version_string,
pcap_version_string);
} else {
/*
* WinPcap version string and packet.dll version
* string are different; that shouldn't be the
* case (the two libraries should come from the
* same version of WinPcap), so we report both
* versions.
*/
full_pcap_version_string_len =
(sizeof pcap_version_string_packet_dll_fmt - 6) +
strlen(wpcap_version_string) +
strlen(packet_version_string) +
strlen(pcap_version_string);
full_pcap_version_string = malloc(full_pcap_version_string_len);
sprintf(full_pcap_version_string,
pcap_version_string_packet_dll_fmt,
wpcap_version_string, packet_version_string,
pcap_version_string);
}
}
return (full_pcap_version_string);
}
#elif defined(MSDOS)
static char *full_pcap_version_string;
const char *
pcap_lib_version (void)
{
char *packet_version_string;
size_t full_pcap_version_string_len;
static char dospfx[] = "DOS-";
if (full_pcap_version_string == NULL) {
/*
* Generate the version string.
*/
full_pcap_version_string_len =
sizeof dospfx + strlen(pcap_version_string);
full_pcap_version_string =
malloc(full_pcap_version_string_len);
strcpy(full_pcap_version_string, dospfx);
strcat(full_pcap_version_string, pcap_version_string);
}
return (full_pcap_version_string);
}
#else /* UN*X */
const char *
pcap_lib_version(void)
{
return (pcap_version_string);
}
#endif

1390
savefile.c

File diff suppressed because it is too large Load Diff