1999-10-07 23:46:40 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
|
|
|
|
* The Regents of the University of 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. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the Computer Systems
|
|
|
|
* Engineering Group at Lawrence Berkeley Laboratory.
|
|
|
|
* 4. Neither the name of the University nor of the Laboratory may be used
|
|
|
|
* to endorse or promote products derived from this software without
|
|
|
|
* specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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[] =
|
2003-03-11 06:23:52 +00:00
|
|
|
"@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.50 2003-03-11 06:23:54 guy Exp $ (LBL)";
|
2000-07-11 00:37:04 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
1999-10-07 23:46:40 +00:00
|
|
|
#endif
|
|
|
|
|
2002-08-02 03:44:19 +00:00
|
|
|
#ifdef WIN32
|
2002-08-01 08:33:01 +00:00
|
|
|
#include <pcap-stdinc.h>
|
2002-08-02 03:44:19 +00:00
|
|
|
#else /* WIN32 */
|
|
|
|
#include <sys/types.h>
|
|
|
|
#endif /* WIN32 */
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2002-08-02 03:44:19 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
2001-12-09 05:10:02 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_OS_PROTO_H
|
|
|
|
#include "os-proto.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "pcap-int.h"
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
|
|
|
{
|
|
|
|
register int n;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (p->sf.rfile != NULL)
|
|
|
|
n = pcap_offline_read(p, cnt, callback, user);
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* XXX keep reading until we get something
|
|
|
|
* (or an error occurs)
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
n = pcap_read(p, cnt, callback, user);
|
|
|
|
} while (n == 0);
|
|
|
|
}
|
|
|
|
if (n <= 0)
|
|
|
|
return (n);
|
|
|
|
if (cnt > 0) {
|
|
|
|
cnt -= n;
|
|
|
|
if (cnt <= 0)
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct singleton {
|
|
|
|
struct pcap_pkthdr *hdr;
|
|
|
|
const u_char *pkt;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
pcap_oneshot(u_char *userData, const struct pcap_pkthdr *h, const u_char *pkt)
|
|
|
|
{
|
|
|
|
struct singleton *sp = (struct singleton *)userData;
|
|
|
|
*sp->hdr = *h;
|
|
|
|
sp->pkt = pkt;
|
|
|
|
}
|
|
|
|
|
|
|
|
const u_char *
|
|
|
|
pcap_next(pcap_t *p, struct pcap_pkthdr *h)
|
|
|
|
{
|
|
|
|
struct singleton s;
|
|
|
|
|
|
|
|
s.hdr = h;
|
|
|
|
if (pcap_dispatch(p, 1, pcap_oneshot, (u_char*)&s) <= 0)
|
|
|
|
return (0);
|
|
|
|
return (s.pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcap_datalink(pcap_t *p)
|
|
|
|
{
|
|
|
|
return (p->linktype);
|
|
|
|
}
|
|
|
|
|
2002-12-19 09:05:45 +00:00
|
|
|
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*)malloc(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) {
|
|
|
|
/*
|
|
|
|
* We couldn't fetch the list of DLTs, 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 (pcap_set_datalink_platform(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;
|
|
|
|
int dlt;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DLT_CHOICE(code) { #code, code }
|
|
|
|
#define DLT_CHOICE_SENTINEL { NULL, 0 }
|
|
|
|
|
|
|
|
static struct dlt_choice dlt_choices[] = {
|
|
|
|
DLT_CHOICE(DLT_ARCNET),
|
2003-01-23 07:24:51 +00:00
|
|
|
DLT_CHOICE(DLT_ARCNET_LINUX),
|
2002-12-19 09:05:45 +00:00
|
|
|
DLT_CHOICE(DLT_EN10MB),
|
|
|
|
DLT_CHOICE(DLT_SLIP),
|
|
|
|
DLT_CHOICE(DLT_SLIP_BSDOS),
|
|
|
|
DLT_CHOICE(DLT_NULL),
|
|
|
|
DLT_CHOICE(DLT_LOOP),
|
|
|
|
DLT_CHOICE(DLT_PPP),
|
|
|
|
DLT_CHOICE(DLT_C_HDLC),
|
|
|
|
DLT_CHOICE(DLT_PPP_SERIAL),
|
|
|
|
DLT_CHOICE(DLT_PPP_ETHER),
|
|
|
|
DLT_CHOICE(DLT_PPP_BSDOS),
|
|
|
|
DLT_CHOICE(DLT_FDDI),
|
|
|
|
DLT_CHOICE(DLT_IEEE802),
|
|
|
|
DLT_CHOICE(DLT_IEEE802_11),
|
|
|
|
DLT_CHOICE(DLT_PRISM_HEADER),
|
|
|
|
DLT_CHOICE(DLT_IEEE802_11_RADIO),
|
|
|
|
DLT_CHOICE(DLT_ATM_RFC1483),
|
|
|
|
DLT_CHOICE(DLT_ATM_CLIP),
|
|
|
|
DLT_CHOICE(DLT_SUNATM),
|
|
|
|
DLT_CHOICE(DLT_RAW),
|
|
|
|
DLT_CHOICE(DLT_LINUX_SLL),
|
|
|
|
DLT_CHOICE(DLT_LTALK),
|
|
|
|
DLT_CHOICE(DLT_IP_OVER_FC),
|
|
|
|
DLT_CHOICE(DLT_FRELAY),
|
|
|
|
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[] = {
|
2003-01-03 08:34:46 +00:00
|
|
|
(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',
|
2002-12-19 09:05:45 +00:00
|
|
|
};
|
|
|
|
|
2003-03-11 06:23:52 +00:00
|
|
|
int
|
2002-12-19 09:05:45 +00:00
|
|
|
pcap_strcasecmp(const char *s1, const char *s2)
|
|
|
|
{
|
|
|
|
register const u_char *cm = charmap,
|
|
|
|
*us1 = (u_char *)s1,
|
|
|
|
*us2 = (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);
|
|
|
|
}
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
int
|
|
|
|
pcap_snapshot(pcap_t *p)
|
|
|
|
{
|
|
|
|
return (p->snapshot);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcap_is_swapped(pcap_t *p)
|
|
|
|
{
|
|
|
|
return (p->sf.swapped);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcap_major_version(pcap_t *p)
|
|
|
|
{
|
|
|
|
return (p->sf.version_major);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcap_minor_version(pcap_t *p)
|
|
|
|
{
|
|
|
|
return (p->sf.version_minor);
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *
|
|
|
|
pcap_file(pcap_t *p)
|
|
|
|
{
|
|
|
|
return (p->sf.rfile);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcap_fileno(pcap_t *p)
|
|
|
|
{
|
2002-08-01 08:33:01 +00:00
|
|
|
#ifndef WIN32
|
1999-10-07 23:46:40 +00:00
|
|
|
return (p->fd);
|
2002-08-01 08:33:01 +00:00
|
|
|
#else
|
|
|
|
if (p->adapter != NULL)
|
|
|
|
return ((int)(DWORD)p->adapter->hFile);
|
|
|
|
else
|
|
|
|
return (-1);
|
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pcap_perror(pcap_t *p, char *prefix)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: %s\n", prefix, p->errbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
pcap_geterr(pcap_t *p)
|
|
|
|
{
|
|
|
|
return (p->errbuf);
|
|
|
|
}
|
|
|
|
|
2001-12-09 05:10:02 +00:00
|
|
|
/*
|
|
|
|
* NOTE: in the future, these may need to call platform-dependent routines,
|
|
|
|
* e.g. on platforms with memory-mapped packet-capture mechanisms where
|
|
|
|
* "pcap_read()" uses "select()" or "poll()" to wait for packets to arrive.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pcap_getnonblock(pcap_t *p, char *errbuf)
|
|
|
|
{
|
2002-08-01 08:33:01 +00:00
|
|
|
#ifndef WIN32
|
2001-12-09 05:10:02 +00:00
|
|
|
int fdflags;
|
2002-08-01 08:33:01 +00:00
|
|
|
#endif
|
2001-12-09 05:10:02 +00:00
|
|
|
|
|
|
|
if (p->sf.rfile != NULL) {
|
|
|
|
/*
|
|
|
|
* This is a savefile, not a live capture file, so
|
|
|
|
* never say it's in non-blocking mode.
|
|
|
|
*/
|
|
|
|
return (0);
|
|
|
|
}
|
2002-08-01 08:33:01 +00:00
|
|
|
#ifndef WIN32
|
2001-12-09 05:10:02 +00:00
|
|
|
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);
|
2002-08-01 08:33:01 +00:00
|
|
|
#else
|
|
|
|
return (p->nonblock);
|
|
|
|
#endif
|
2001-12-09 05:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)
|
|
|
|
{
|
2002-08-01 08:33:01 +00:00
|
|
|
#ifndef WIN32
|
2001-12-09 05:10:02 +00:00
|
|
|
int fdflags;
|
2002-08-01 08:33:01 +00:00
|
|
|
#else
|
|
|
|
int newtimeout;
|
|
|
|
#endif
|
2001-12-09 05:10:02 +00:00
|
|
|
|
|
|
|
if (p->sf.rfile != NULL) {
|
|
|
|
/*
|
|
|
|
* This is a savefile, not a live capture file, so
|
|
|
|
* ignore requests to put it in non-blocking mode.
|
|
|
|
*/
|
|
|
|
return (0);
|
|
|
|
}
|
2002-08-01 08:33:01 +00:00
|
|
|
#ifndef WIN32
|
2001-12-09 05:10:02 +00:00
|
|
|
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);
|
|
|
|
}
|
2002-08-01 08:33:01 +00:00
|
|
|
#else
|
|
|
|
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);
|
|
|
|
#endif
|
2001-12-29 21:55:32 +00:00
|
|
|
return (0);
|
2001-12-09 05:10:02 +00:00
|
|
|
}
|
|
|
|
|
2002-08-01 08:33:01 +00:00
|
|
|
#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;
|
|
|
|
|
|
|
|
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';
|
|
|
|
}
|
|
|
|
return (errbuf);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
/*
|
|
|
|
* Not all systems have strerror().
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
pcap_strerror(int errnum)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_STRERROR
|
|
|
|
return (strerror(errnum));
|
|
|
|
#else
|
|
|
|
extern int sys_nerr;
|
|
|
|
extern const char *const sys_errlist[];
|
|
|
|
static char ebuf[20];
|
|
|
|
|
|
|
|
if ((unsigned int)errnum < sys_nerr)
|
|
|
|
return ((char *)sys_errlist[errnum]);
|
2000-04-27 09:11:11 +00:00
|
|
|
(void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
|
1999-10-07 23:46:40 +00:00
|
|
|
return(ebuf);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2000-06-26 04:58:04 +00:00
|
|
|
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));
|
2002-08-01 08:33:01 +00:00
|
|
|
#ifndef WIN32
|
2000-06-26 04:58:04 +00:00
|
|
|
p->fd = -1;
|
2002-08-01 08:33:01 +00:00
|
|
|
#else
|
|
|
|
p->adapter = NULL;
|
|
|
|
#endif /* WIN32 */
|
2000-06-26 04:58:04 +00:00
|
|
|
p->snapshot = snaplen;
|
|
|
|
p->linktype = linktype;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
void
|
|
|
|
pcap_close(pcap_t *p)
|
|
|
|
{
|
|
|
|
/*XXX*/
|
2002-08-01 08:33:01 +00:00
|
|
|
#ifndef WIN32
|
Clean up promiscuous mode, when using SOCK_PACKET, as best we can;
remember which pcap_t's were opened (with SOCK_PACKET) in promiscuous
mode on interfaces not already in promiscuous mode, turn promiscuous
mode off when closing such a pcap_t, and arrange that, when the program
exits, all pcap_t's of that sort not already closed have their
interfaces taken out of promiscuous mode. (It's not sufficient to do
this on exit - applications may close a pcap_t without exiting, e.g.
Ethereal.)
This won't always work right (if somebody else requests promiscuous mode
after it's opened by libpcap, we'll turn promiscuous mode off when we
close the pcap_t, and if the program doesn't exit cleanly, it won't
clean up the interfaces), but neither of those problems are fixable -
the only way to get things to work correctly is to use PF_PACKET
sockets, which requires a 2.2 or later kernel.
On a 2.0[.x] kernel, when doing a "recvfrom()" on a SOCK_PACKET socket
to read a captured packet, don't pass a byte count value based on the
snapshot length - "recvfrom()" won't return the actual packet length if
you do that. (2.2 and later kernels will return the actual packet
length if MSG_TRUNC is passed in.)
2000-12-16 10:43:26 +00:00
|
|
|
if (p->fd >= 0) {
|
|
|
|
#ifdef linux
|
|
|
|
pcap_close_linux(p);
|
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
close(p->fd);
|
Clean up promiscuous mode, when using SOCK_PACKET, as best we can;
remember which pcap_t's were opened (with SOCK_PACKET) in promiscuous
mode on interfaces not already in promiscuous mode, turn promiscuous
mode off when closing such a pcap_t, and arrange that, when the program
exits, all pcap_t's of that sort not already closed have their
interfaces taken out of promiscuous mode. (It's not sufficient to do
this on exit - applications may close a pcap_t without exiting, e.g.
Ethereal.)
This won't always work right (if somebody else requests promiscuous mode
after it's opened by libpcap, we'll turn promiscuous mode off when we
close the pcap_t, and if the program doesn't exit cleanly, it won't
clean up the interfaces), but neither of those problems are fixable -
the only way to get things to work correctly is to use PF_PACKET
sockets, which requires a 2.2 or later kernel.
On a 2.0[.x] kernel, when doing a "recvfrom()" on a SOCK_PACKET socket
to read a captured packet, don't pass a byte count value based on the
snapshot length - "recvfrom()" won't return the actual packet length if
you do that. (2.2 and later kernels will return the actual packet
length if MSG_TRUNC is passed in.)
2000-12-16 10:43:26 +00:00
|
|
|
}
|
2002-08-02 03:44:19 +00:00
|
|
|
#else /* WIN32 */
|
2002-08-01 08:33:01 +00:00
|
|
|
if (p->adapter != NULL) {
|
|
|
|
PacketCloseAdapter(p->adapter);
|
|
|
|
p->adapter = NULL;
|
|
|
|
}
|
|
|
|
#endif /* WIN32 */
|
1999-10-07 23:46:40 +00:00
|
|
|
if (p->sf.rfile != NULL) {
|
2000-08-13 10:33:14 +00:00
|
|
|
if (p->sf.rfile != stdin)
|
|
|
|
(void)fclose(p->sf.rfile);
|
1999-10-07 23:46:40 +00:00
|
|
|
if (p->sf.base != NULL)
|
|
|
|
free(p->sf.base);
|
|
|
|
} else if (p->buffer != NULL)
|
|
|
|
free(p->buffer);
|
2003-01-16 07:44:27 +00:00
|
|
|
if (p->dlt_list != NULL)
|
|
|
|
free(p->dlt_list);
|
2002-06-11 17:04:44 +00:00
|
|
|
|
2000-10-28 00:01:26 +00:00
|
|
|
pcap_freecode(&p->fcode);
|
1999-10-07 23:46:40 +00:00
|
|
|
free(p);
|
|
|
|
}
|
2003-02-11 07:40:09 +00:00
|
|
|
|
|
|
|
/*
|
At least on SunOS 5.x, Digital UNIX 4.0, AIX 4.3, FreeBSD 3.4, some
version of Red Hat Linux, HP-UX 11.00, and MacOS X 10.1, if a string in
a shared library is static, and returned by a function in that library,
the return value of that function, when called from a program, will
reflect the contents of the string in the version of the shared library
with which the program is running, not the version with which it's
linked.
Therefore we can just generate a definition of the version string and
put it into "version.h", which means that VERSION can contain any string
(as long as " and \ are escaped with \) rather than having to be N.M or
N.M.MM.
2003-02-13 07:54:59 +00:00
|
|
|
* 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).
|
2003-02-11 07:40:09 +00:00
|
|
|
*/
|
2003-02-11 07:50:03 +00:00
|
|
|
#ifdef WIN32
|
At least on SunOS 5.x, Digital UNIX 4.0, AIX 4.3, FreeBSD 3.4, some
version of Red Hat Linux, HP-UX 11.00, and MacOS X 10.1, if a string in
a shared library is static, and returned by a function in that library,
the return value of that function, when called from a program, will
reflect the contents of the string in the version of the shared library
with which the program is running, not the version with which it's
linked.
Therefore we can just generate a definition of the version string and
put it into "version.h", which means that VERSION can contain any string
(as long as " and \ are escaped with \) rather than having to be N.M or
N.M.MM.
2003-02-13 07:54:59 +00:00
|
|
|
/*
|
|
|
|
* XXX - it'd be nice if we could somehow generate this when building WinPcap.
|
|
|
|
*/
|
|
|
|
static const char pcap_version_string[] =
|
|
|
|
"WinPcap version 3.0beta, based on libpcap version 0.8";
|
2003-02-11 08:01:40 +00:00
|
|
|
#else
|
At least on SunOS 5.x, Digital UNIX 4.0, AIX 4.3, FreeBSD 3.4, some
version of Red Hat Linux, HP-UX 11.00, and MacOS X 10.1, if a string in
a shared library is static, and returned by a function in that library,
the return value of that function, when called from a program, will
reflect the contents of the string in the version of the shared library
with which the program is running, not the version with which it's
linked.
Therefore we can just generate a definition of the version string and
put it into "version.h", which means that VERSION can contain any string
(as long as " and \ are escaped with \) rather than having to be N.M or
N.M.MM.
2003-02-13 07:54:59 +00:00
|
|
|
#include "version.h"
|
2003-02-11 07:50:03 +00:00
|
|
|
#endif
|
At least on SunOS 5.x, Digital UNIX 4.0, AIX 4.3, FreeBSD 3.4, some
version of Red Hat Linux, HP-UX 11.00, and MacOS X 10.1, if a string in
a shared library is static, and returned by a function in that library,
the return value of that function, when called from a program, will
reflect the contents of the string in the version of the shared library
with which the program is running, not the version with which it's
linked.
Therefore we can just generate a definition of the version string and
put it into "version.h", which means that VERSION can contain any string
(as long as " and \ are escaped with \) rather than having to be N.M or
N.M.MM.
2003-02-13 07:54:59 +00:00
|
|
|
|
|
|
|
const char *
|
|
|
|
pcap_lib_version(void)
|
|
|
|
{
|
|
|
|
return (pcap_version_string);
|
2003-02-11 07:40:09 +00:00
|
|
|
}
|