?? pcap-linux.c
字號(hào):
*
* We count them here even if we can get the packet count
* from the kernel, as we can only determine at run time
* whether we'll be able to get it from the kernel (if
* HAVE_TPACKET_STATS isn't defined, we can't get it from
* the kernel, but if it is defined, the library might
* have been built with a 2.4 or later kernel, but we
* might be running on a 2.2[.x] kernel without Alexey
* Kuznetzov's turbopacket patches, and thus the kernel
* might not be able to supply those statistics). We
* could, I guess, try, when opening the socket, to get
* the statistics, and if we can not increment the count
* here, but it's not clear that always incrementing
* the count is more expensive than always testing a flag
* in memory.
*/
handle->md.stat.ps_recv++;
(*pkt_data)= bp;
(*pkt_header)= &(handle->pcap_header);
return 1;
}
else
{
/* We are on an offline capture */
struct bpf_insn *fcode = handle->fcode.bf_insns;
int status;
int n = 0;
while (1)
{
status = sf_next_packet(handle, &handle->pcap_header, handle->buffer, handle->bufsize);
if (status==1)
/* EOF */
return (-2);
if (status==-1)
/* Error */
return (-1);
if (fcode == NULL ||
bpf_filter(fcode, handle->buffer, handle->pcap_header.len, handle->pcap_header.caplen))
{
*pkt_header = &handle->pcap_header;
*pkt_data = handle->buffer;
return (1);
}
}
}
}
#endif /* HAVE_PCAPREADEX */
/*
* Get the statistics for the given packet capture handle.
* Reports the number of dropped packets iff the kernel supports
* the PACKET_STATISTICS "getsockopt()" argument (2.4 and later
* kernels, and 2.2[.x] kernels with Alexey Kuznetzov's turbopacket
* patches); otherwise, that information isn't available, and we lie
* and report 0 as the count of dropped packets.
*/
int
pcap_stats(pcap_t *handle, struct pcap_stat *stats)
{
#ifdef HAVE_TPACKET_STATS
struct tpacket_stats kstats;
socklen_t len = sizeof (struct tpacket_stats);
#endif
#ifdef REMOTE
if (handle->rmt_clientside)
{
/* We are on an remote capture */
return pcap_stats_remote(handle, stats);
}
#endif
#ifdef HAVE_TPACKET_STATS
/*
* Try to get the packet counts from the kernel.
*/
if (getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS,
&kstats, &len) > -1) {
/*
* In "linux/net/packet/af_packet.c", at least in the
* 2.4.9 kernel, "tp_packets" is incremented for every
* packet that passes the packet filter *and* is
* successfully queued on the socket; "tp_drops" is
* incremented for every packet dropped because there's
* not enough free space in the socket buffer.
*
* When the statistics are returned for a PACKET_STATISTICS
* "getsockopt()" call, "tp_drops" is added to "tp_packets",
* so that "tp_packets" counts all packets handed to
* the PF_PACKET socket, including packets dropped because
* there wasn't room on the socket buffer - but not
* including packets that didn't pass the filter.
*
* In the BSD BPF, the count of received packets is
* incremented for every packet handed to BPF, regardless
* of whether it passed the filter.
*
* We can't make "pcap_stats()" work the same on both
* platforms, but the best approximation is to return
* "tp_packets" as the count of packets and "tp_drops"
* as the count of drops.
*/
handle->md.stat.ps_recv = kstats.tp_packets;
handle->md.stat.ps_drop = kstats.tp_drops;
}
else
{
/*
* If the error was EOPNOTSUPP, fall through, so that
* if you build the library on a system with
* "struct tpacket_stats" and run it on a system
* that doesn't, it works as it does if the library
* is built on a system without "struct tpacket_stats".
*/
if (errno != EOPNOTSUPP) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"pcap_stats: %s", pcap_strerror(errno));
return -1;
}
}
#endif
/*
* On systems where the PACKET_STATISTICS "getsockopt()" argument
* is supported on PF_PACKET sockets:
*
* "ps_recv" counts only packets that *passed* the filter,
* not packets that didn't pass the filter. This includes
* packets later dropped because we ran out of buffer space.
*
* "ps_drop" counts packets dropped because we ran out of
* buffer space. It doesn't count packets dropped by the
* interface driver. It counts only packets that passed
* the filter.
*
* Both statistics include packets not yet read from the
* kernel by libpcap, and thus not yet seen by the application.
*
* On systems where the PACKET_STATISTICS "getsockopt()" argument
* is not supported on PF_PACKET sockets:
*
* "ps_recv" counts only packets that *passed* the filter,
* not packets that didn't pass the filter. It does not
* count packets dropped because we ran out of buffer
* space.
*
* "ps_drop" is not supported.
*
* "ps_recv" doesn't include packets not yet read from
* the kernel by libpcap.
*/
*stats = handle->md.stat;
return 0;
}
/*
* Description string for the "any" device.
*/
static const char any_descr[] = "Pseudo-device that captures on all interfaces";
int
pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
{
if (pcap_add_if(alldevsp, "any", 0, any_descr, errbuf) < 0)
return (-1);
return (0);
}
/*
* Attach the given BPF code to the packet capture device.
*/
int
pcap_setfilter(pcap_t *handle, struct bpf_program *filter)
{
#ifdef SO_ATTACH_FILTER
struct sock_fprog fcode;
int can_filter_in_kernel;
int err = 0;
#endif
if (!handle)
return -1;
if (!filter) {
strncpy(handle->errbuf, "setfilter: No filter specified",
sizeof(handle->errbuf));
return -1;
}
#ifdef REMOTE
if (handle->rmt_clientside)
{
/* We are on an remote capture */
return pcap_setfilter_remote(handle, filter);
}
#endif
/* Make our private copy of the filter */
if (install_bpf_program(handle, filter) < 0)
/* install_bpf_program() filled in errbuf */
return -1;
/*
* Run user level packet filter by default. Will be overriden if
* installing a kernel filter succeeds.
*/
handle->md.use_bpf = 0;
/*
* If we're reading from a savefile, don't try to install
* a kernel filter.
*/
if (handle->sf.rfile != NULL)
return 0;
/* Install kernel level filter if possible */
#ifdef SO_ATTACH_FILTER
#ifdef USHRT_MAX
if (handle->fcode.bf_len > USHRT_MAX) {
/*
* fcode.len is an unsigned short for current kernel.
* I have yet to see BPF-Code with that much
* instructions but still it is possible. So for the
* sake of correctness I added this check.
*/
fprintf(stderr, "Warning: Filter too complex for kernel\n");
fcode.filter = NULL;
can_filter_in_kernel = 0;
} else
#endif /* USHRT_MAX */
{
/*
* Oh joy, the Linux kernel uses struct sock_fprog instead
* of struct bpf_program and of course the length field is
* of different size. Pointed out by Sebastian
*
* Oh, and we also need to fix it up so that all "ret"
* instructions with non-zero operands have 65535 as the
* operand, and so that, if we're in cooked mode, all
* memory-reference instructions use special magic offsets
* in references to the link-layer header and assume that
* the link-layer payload begins at 0; "fix_program()"
* will do that.
*/
switch (fix_program(handle, &fcode)) {
case -1:
default:
/*
* Fatal error; just quit.
* (The "default" case shouldn't happen; we
* return -1 for that reason.)
*/
return -1;
case 0:
/*
* The program performed checks that we can't make
* work in the kernel.
*/
can_filter_in_kernel = 0;
break;
case 1:
/*
* We have a filter that'll work in the kernel.
*/
can_filter_in_kernel = 1;
break;
}
}
if (can_filter_in_kernel) {
if ((err = set_kernel_filter(handle, &fcode)) == 0)
{
/* Installation succeded - using kernel filter. */
handle->md.use_bpf = 1;
}
else if (err == -1) /* Non-fatal error */
{
/*
* Print a warning if we weren't able to install
* the filter for a reason other than "this kernel
* isn't configured to support socket filters.
*/
if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) {
fprintf(stderr,
"Warning: Kernel filter failed: %s\n",
pcap_strerror(errno));
}
}
}
/*
* If we're not using the kernel filter, get rid of any kernel
* filter that might've been there before, e.g. because the
* previous filter could work in the kernel, or because some other
* code attached a filter to the socket by some means other than
* calling "pcap_setfilter()". Otherwise, the kernel filter may
* filter out packets that would pass the new userland filter.
*/
if (!handle->md.use_bpf)
reset_kernel_filter(handle);
/*
* Free up the copy of the filter that was made by "fix_program()".
*/
if (fcode.filter != NULL)
free(fcode.filter);
if (err == -2)
/* Fatal error */
return -1;
#endif /* SO_ATTACH_FILTER */
return 0;
}
/*
* Linux uses the ARP hardware type to identify the type of an
* interface. pcap uses the DLT_xxx constants for this. This
* function takes a pointer to a "pcap_t", and an ARPHRD_xxx
* constant, as arguments, and sets "handle->linktype" to the
* appropriate DLT_XXX constant and sets "handle->offset" to
* the appropriate value (to make "handle->offset" plus link-layer
* header length be a multiple of 4, so that the link-layer payload
* will be aligned on a 4-byte boundary when capturing packets).
* (If the offset isn't set here, it'll be 0; add code as appropriate
* for cases where it shouldn't be 0.)
*
* If "cooked_ok" is non-zero, we can use DLT_LINUX_SLL and capture
* in cooked mode; otherwise, we can't use cooked mode, so we have
* to pick some type that works in raw mode, or fail.
*
* Sets the link type to -1 if unable to map the type.
*/
static void map_arphrd_to_dlt(pcap_t *handle, int arptype, int cooked_ok)
{
switch (arptype) {
case ARPHRD_ETHER:
case ARPHRD_METRICOM:
case ARPHRD_LOOPBACK:
handle->linktype = DLT_EN10MB;
handle->offset = 2;
break;
case ARPHRD_EETHER:
handle->linktype = DLT_EN3MB;
break;
case ARPHRD_AX25:
handle->linktype = DLT_AX25;
break;
case ARPHRD_PRONET:
handle->linktype = DLT_PRONET;
break;
case ARPHRD_CHAOS:
handle->linktype = DLT_CHAOS;
break;
#ifndef ARPHRD_IEEE802_TR
#define ARPHRD_IEEE802_TR 800 /* From Linux 2.4 */
#endif
case ARPHRD_IEEE802_TR:
case ARPHRD_IEEE802:
handle->linktype = DLT_IEEE802;
handle->offset = 2;
break;
case ARPHRD_ARCNET:
handle->linktype = DLT_ARCNET_LINUX;
break;
#ifndef ARPHRD_FDDI /* From Linux 2.2.13 */
#define ARPHRD_FDDI 774
#endif
case ARPHRD_FDDI:
handle->linktype = DLT_FDDI;
handle->offset = 3;
break;
#ifndef ARPHRD_ATM /* FIXME: How to #include this? */
#define ARPHRD_ATM 19
#endif
case ARPHRD_ATM:
/*
* The Classical IP implementation in ATM for Linux
* supports both what RFC 1483 calls "LLC Encapsulation",
* in which each packet has an LLC header, possibly
* with a SNAP header as well, prepended to it, and
* what RFC 1483 calls "VC Based Multiplexing", in which
* different virtual circuits carry different network
* layer protocols, and no header is prepended to packets.
*
* They both have an ARPHRD_ type of ARPHRD_ATM, so
* you can't use the ARPHRD_ type to find out whether
* captured packets will have an LLC header, and,
* while there's a socket ioctl to *set* the encapsulation
* type, there's no ioctl to *get* the encapsulation type.
*
* This means that
*
* programs that dissect Linux Classical IP frames
* would have to check for an LLC header and,
* depending on whether they see one or not, dissect
* the frame as LLC-encapsulated or as raw IP (I
* don't know whether there's any traffic other than
* IP that would show up on the socket, or whether
* there's any support for IPv6 in the Linux
* Classical IP code);
*
* filter expressions would have to compile into
* code that checks for an LLC header and does
* the right thing.
*
* Both of those are a nuisance - and, at least on systems
* that support PF_PACKET sockets, we don't have to put
* up with those nuisances; instead, we can just capture
* in cooked mode. That's what we'll do, if we can.
* Otherwise, we'll just fail.
*/
if (cooked_ok)
handle->linktype = DLT_LINUX_SLL;
else
handle->linktype = -1;
break;
#ifndef ARPHRD_IEEE80211 /* From Linux 2.4.6 */
#define ARPHRD_IEEE80211 801
#endif
case ARPHRD_IEEE80211:
handle->linktype = DLT_IEEE802_11;
break;
#ifndef ARPHRD_IEEE80211_PRISM /* From Linux 2.4.18 */
#define ARPHRD_IEEE80211_PRISM 802
#endif
case ARPHRD_IEEE80211_PRISM:
handle->linktype = DLT_PRISM_HEADER;
break;
case ARPHRD_PPP:
/*
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -