hey guys,
i've modified a bit of the pcap code, just regarding the pcap_read_packet
function callback and a few of the wrappers for it. I'm getting a bunch of
errors when I add the code from the attached txt file to it, it gives errors
about pointers eg
ar.c:395: dereferencing pointer to incomplete type
now this happens on lines of code that have pcap_t as you can see I haven't
modified pcap_t at all so i'm a little confused why i'm getting this error.
any asisstance would be greatly appreciated.
Regards,
Iain McAleer
typedef int (*ais_pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *);
int ais_pcap_loop(pcap_t *p, int cnt, ais_pcap_handler callback, u_char *user);
int ais_pcap_read(pcap_t *handle, int max_packets, ais_pcap_handler callback, u_char
*user);
static int ais_pcap_read_packet(pcap_t *handle, ais_pcap_handler callback, u_char
*userdata);
int ais_pcap_loop(pcap_t *p, int cnt, ais_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 = ais_pcap_read(p, cnt, callback, user);
} while (n == 0);
}
if (n < 0)
return (n);
if (n > 0)
return (n);
if (cnt > 0) {
cnt -= n;
if (cnt <= 0)
return (0);
}
}
}
int ais_pcap_read(pcap_t *handle, int max_packets, ais_pcap_handler callback, u_char
*user)
{
/*
* Currently, on Linux only one packet is delivered per read,
* so we don't loop.
*/
return ais_pcap_read_packet(handle, callback, user);
}
static int ais_pcap_read_packet(pcap_t *handle, ais_pcap_handler callback, u_char
*userdata)
{
int offset;
#ifdef HAVE_PF_PACKET_SOCKETS
struct sockaddr_ll from;
struct sll_header *hdrp;
#else
struct sockaddr from;
#endif
socklen_t fromlen;
int packet_len, caplen;
struct pcap_pkthdr pcap_header;
#ifdef HAVE_PF_PACKET_SOCKETS
/*
* If this is a cooked device, leave extra room for a
* fake packet header.
*/
if (handle->md.cooked)
offset = SLL_HDR_LEN;
else
offset = 0;
#else
/*
* This system doesn't have PF_PACKET sockets, so it doesn't
* support cooked devices.
*/
offset = 0;
#endif
/* Receive a single packet from the kernel */
do {
fromlen = sizeof(from);
packet_len = recvfrom(
handle->fd, handle->buffer + offset + handle->offset,
handle->md.readlen - offset, MSG_TRUNC,
(struct sockaddr *) &from, &fromlen);
} while (packet_len == -1 && errno == EINTR);
/* Check if an error occured */
if (packet_len == -1) {
if (errno == EAGAIN)
return 0; /* no packet there */
else {
snprintf(handle->errbuf, sizeof(handle->errbuf),
"recvfrom: %s", pcap_strerror(errno));
return -1;
}
}
#ifdef HAVE_PF_PACKET_SOCKETS
/*
* If this is from the loopback device, reject outgoing packets;
* we'll see the packet as an incoming packet as well, and
* we don't want to see it twice.
*
* We can only do this if we're using PF_PACKET; the address
* returned for SOCK_PACKET is a "sockaddr_pkt" which lacks
* the relevant packet type information.
*/
if (!handle->md.sock_packet &&
from.sll_ifindex == handle->md.lo_ifindex &&
from.sll_pkttype == PACKET_OUTGOING)
return 0;
#endif
#ifdef HAVE_PF_PACKET_SOCKETS
/*
* If this is a cooked device, fill in the fake packet header.
*/
if (handle->md.cooked) {
/*
* Add the length of the fake header to the length
* of packet data we read.
*/
packet_len += SLL_HDR_LEN;
hdrp = (struct sll_header *)handle->buffer;
/*
* Map the PACKET_ value to a LINUX_SLL_ value; we
* want the same numerical value to be used in
* the link-layer header even if the numerical values
* for the PACKET_ #defines change, so that programs
* that look at the packet type field will always be
* able to handle DLT_LINUX_SLL captures.
*/
switch (from.sll_pkttype) {
case PACKET_HOST:
hdrp->sll_pkttype = htons(LINUX_SLL_HOST);
break;
case PACKET_BROADCAST:
hdrp->sll_pkttype = htons(LINUX_SLL_BROADCAST);
break;
case PACKET_MULTICAST:
hdrp->sll_pkttype = htons(LINUX_SLL_MULTICAST);
break;
case PACKET_OTHERHOST:
hdrp->sll_pkttype = htons(LINUX_SLL_OTHERHOST);
break;
case PACKET_OUTGOING:
hdrp->sll_pkttype = htons(LINUX_SLL_OUTGOING);
break;
default:
hdrp->sll_pkttype = -1;
break;
}
hdrp->sll_hatype = htons(from.sll_hatype);
hdrp->sll_halen = htons(from.sll_halen);
memcpy(hdrp->sll_addr, from.sll_addr,
(from.sll_halen > SLL_ADDRLEN) ?
SLL_ADDRLEN :
from.sll_halen);
hdrp->sll_protocol = from.sll_protocol;
}
#endif
/*
* XXX: According to the kernel source we should get the real
* packet len if calling recvfrom with MSG_TRUNC set. It does
* not seem to work here :(, but it is supported by this code
* anyway.
* To be honest the code RELIES on that feature so this is really
* broken with 2.2.x kernels.
* I spend a day to figure out what's going on and I found out
* that the following is happening:
*
* The packet comes from a random interface and the packet_rcv
* hook is called with a clone of the packet. That code inserts
* the packet into the receive queue of the packet socket.
* If a filter is attached to that socket that filter is run
* first - and there lies the problem. The default filter always
* cuts the packet at the snaplen:
*
* # tcpdump -d
* (000) ret #68
*
* So the packet filter cuts down the packet. The recvfrom call
* says "hey, it's only 68 bytes, it fits into the buffer" with
* the result that we don't get the real packet length. This
* is valid at least until kernel 2.2.17pre6.
*
* We currently handle this by making a copy of the filter
* program, fixing all "ret" instructions with non-zero
* operands to have an operand of 65535 so that the filter
* doesn't truncate the packet, and supplying that modified
* filter to the kernel.
*/
caplen = packet_len;
if (caplen > handle->snapshot)
caplen = handle->snapshot;
/* Run the packet filter if not using kernel filter */
if (!handle->md.use_bpf && handle->fcode.bf_insns) {
if (bpf_filter(handle->fcode.bf_insns, handle->buffer,
packet_len, caplen) == 0)
{
/* rejected by filter */
return 0;
}
}
/* Fill in our own header data */
if (ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1) {
snprintf(handle->errbuf, sizeof(handle->errbuf),
"ioctl: %s", pcap_strerror(errno));
return -1;
}
pcap_header.caplen = caplen;
pcap_header.len = packet_len;
/* Call the user supplied callback function */
handle->md.stat.ps_recv++;
return callback(userdata, &pcap_header, handle->buffer + handle->offset);
return 1;
}