📄 pcap-remote.c
字号:
// addrinfo is no longer used
freeaddrinfo(addrinfo);
addrinfo= NULL;
}
else
{
SOCKET socktemp; // We need another socket, since we're going to accept() a connection
// Connection creation
saddrlen = sizeof(struct sockaddr_storage);
socktemp= accept(sockdata, (struct sockaddr *) &saddr, &saddrlen);
if (socktemp == -1)
{
sock_geterror("accept(): ", fp->errbuf, PCAP_ERRBUF_SIZE);
goto error;
}
// Now that I accepted the connection, the server socket is no longer needed
sock_close(sockdata, fp->errbuf, PCAP_ERRBUF_SIZE);
sockdata= socktemp;
}
}
// Let's save the socket of the data connection
fp->rmt_sockdata= sockdata;
// Allocates WinPcap/libpcap user buffer, which is a socket buffer in case of a remote capture
// It has the same size of the one used on the other side of the connection
fp->bufsize= ntohl(startcapreply.bufsize);
// Let's get the actual size of the socket buffer
itemp= sizeof(sockbufsize);
res= getsockopt(sockdata, SOL_SOCKET, SO_RCVBUF, (char *) &sockbufsize, &itemp);
if (res == -1)
{
sock_geterror("pcap_startcapture_remote()", fp->errbuf, PCAP_ERRBUF_SIZE);
SOCK_ASSERT(fp->errbuf, 1);
}
/*
Warning: on some kernels (e.g. linux), the size of the user buffer does not take
into account the pcap_header and such, and it is set equal to the snaplen.
In my view, this is wrong (the meaning of the bufsize becames a bit strange).
So, here bufsize is the whole size of the user buffer.
In case the bufsize returned is too small, let's adjust it accordingly.
*/
if (fp->bufsize <= fp->snapshot)
fp->bufsize+= sizeof (struct pcap_pkthdr);
// if the current socket buffer is smaller than the desired one
if (sockbufsize < fp->bufsize)
{
// Loop until the buffer size is OK or the original socket buffer size is larger than this one
while (1)
{
res= setsockopt(sockdata, SOL_SOCKET, SO_RCVBUF, (char *) &(fp->bufsize), sizeof(fp->bufsize) );
if (res == 0)
break;
// If something goes wrong, half the buffer size (checking that it does not become smaller than
// the current one)
fp->bufsize/= 2;
if (sockbufsize >= fp->bufsize)
{
fp->bufsize= sockbufsize;
break;
}
}
}
// Let's allocate the packet; this is required in order to put the packet somewhere when
// extracting data from the socket
// Since buffering has already been done in the socket buffer, here we need just a buffer,
// whose size is equal to the pcap header plus the snapshot length
fp->bufsize= fp->snapshot + sizeof (struct pcap_pkthdr);
fp->buffer = (u_char *) malloc(fp->bufsize);
if (fp->buffer == NULL)
{
snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
goto error;
}
// Checks if all the data has been read; if not, discard the data in excess
if (nread != ntohl(header.plen))
{
if (sock_discard(fp->rmt_sockctrl, ntohl(header.plen) - nread, NULL, 0) == 1)
goto error;
}
// In case the user does not want to capture RPCAP packets, let's update the filter
// We have to update it here (instead of sending it into the 'StartCapture' message
// because when we generate the 'start capture' we do not know (yet) all the ports
// we're currently using.
if (fp->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP)
{
struct bpf_program fcode;
if (pcap_createfilter_norpcappkt(fp, &fcode) == -1)
goto error;
// We cannot use 'pcap_setfilter_remote' because formally the capture has not been started yet
// (the 'fp->rmt_capstarted' variable will be updated some lines below)
if (pcap_updatefilter_remote(fp, &fcode) == -1)
goto error;
pcap_freecode(&fcode);
}
fp->rmt_capstarted= 1;
return 0;
error:
// When the connection has been established, we have to close it. So, at the
// beginning of this function, if an error occur we return immediately with
// a return NULL; when the connection is established, we have to come here
// ('goto error;') in order to close everything properly.
// Checks if all the data has been read; if not, discard the data in excess
if (nread != ntohl(header.plen))
sock_discard(fp->rmt_sockctrl, ntohl(header.plen) - nread, NULL, 0);
if ((sockdata) && (sockdata != -1)) // we can be here because sockdata said 'error'
sock_close(sockdata, NULL, 0);
if (!active)
sock_close(fp->rmt_sockctrl, NULL, 0);
// We do not have to call pcap_close() here, because this function is always called
// by the user in case something bad happens
// if (fp)
// {
// pcap_close(fp);
// fp= NULL;
// }
return -1;
}
/*!
\brief Takes a bpf program and sends it to the other host.
This function can be called in two cases:
- the pcap_startcapture() is called (we have to send the filter along with
the 'start capture' command)
- we want to udpate the filter during a capture (i.e. the pcap_setfilter()
is called when the capture is still on)
This function serializes the filter into the sending buffer ('sendbuf', passed
as a parameter) and return back. It does not send anything on the network.
\param fp: the pcap_t descriptor of the device currently opened.
\param sendbuf: the buffer on which the serialized data has to copied.
\param sendbufidx: it is used to return the abounf of bytes copied into the buffer.
\param prog: the bpf program we have to copy.
\return '0' if everything is fine, '-1' otherwise. The error message (if one)
is returned into the 'errbuf' field of the pcap_t structure.
*/
int pcap_pack_bpffilter(pcap_t *fp, char *sendbuf, int *sendbufidx, struct bpf_program *prog)
{
struct rpcap_filter *filter;
struct rpcap_filterbpf_insn *insn;
struct bpf_insn *bf_insn;
struct bpf_program fake_prog; // To be used just in case the user forgot to set a filter
unsigned int i;
if (prog->bf_len == 0) // No filters have been specified; so, let's apply a "fake" filter
{
if (pcap_compile(fp, &fake_prog, NULL /*buffer*/, 1, 0) == -1)
return -1;
prog= &fake_prog;
}
filter= (struct rpcap_filter *) sendbuf;
if ( sock_bufferize(NULL, sizeof(struct rpcap_filter), NULL, sendbufidx,
RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE) )
return -1;
filter->filtertype= htons(RPCAP_UPDATEFILTER_BPF);
filter->nitems= htonl( (int32) prog->bf_len);
if ( sock_bufferize(NULL, prog->bf_len * sizeof(struct rpcap_filterbpf_insn),
NULL, sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE) )
return -1;
insn= (struct rpcap_filterbpf_insn *) (filter + 1);
bf_insn= prog->bf_insns;
for (i= 0; i < prog->bf_len; i++)
{
insn->code= htons(bf_insn->code);
insn->jf= bf_insn->jf;
insn->jt= bf_insn->jt;
insn->k= htonl(bf_insn->k);
insn++;
bf_insn++;
}
return 0;
}
/*! \ingroup remote_pri_func
\brief Update a filter on a remote host.
This function is called when the user wants to update a filter.
In case we're capturing from the network, it sends the filter to the other peer.
This function is *not* called automatically when the user calls the pcap_setfilter().
There will be two cases:
- the capture is already on: in this case, pcap_setfilter() calls pcap_updatefilter_remote()
- the capture has not started yet: in this case, pcap_setfilter() stores the filter into
the pcap_t structure, and then the filter is sent with the pcap_startcap().
Parameters and return values are exactly the same of the pcap_setfilter().
\warning This function *does not* clear the packet currently into the buffers. Therefore,
the user has to expect to receive some packets that are related to the previous filter.
If you want to discard all the packets before applying a new filter, you have to close
the current capture session and start a new one.
*/
int pcap_updatefilter_remote(pcap_t *fp, struct bpf_program *prog)
{
int retval; // general variable used to keep the return value of other functions
char sendbuf[RPCAP_NETBUF_SIZE];// temporary buffer in which data to be sent is buffered
int sendbufidx= 0; // index which keeps the number of bytes currently buffered
struct rpcap_header header; // To keep the reply message
if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE) )
return -1;
rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_UPDATEFILTER_REQ, 0,
sizeof(struct rpcap_filter) + prog->bf_len * sizeof(struct rpcap_filterbpf_insn));
if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, prog) )
return -1;
if ( sock_send(fp->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf, PCAP_ERRBUF_SIZE) )
return -1;
// Waits for the answer
if (sock_recv(fp->rmt_sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
return -1;
// Checks if the message is correct
retval= rpcap_checkmsg(fp->errbuf, fp->rmt_sockctrl, &header, RPCAP_MSG_UPDATEFILTER_REPLY, 0);
if (retval != RPCAP_MSG_UPDATEFILTER_REPLY) // the message is not the one expected
{
switch (retval)
{
case -3: // Unrecoverable network error
case -2: // The other endpoint sent a message that is not allowed here
case -1: // The other endpoint has a version number that is not compatible with our
// Do nothing; just exit from here; the error code is already into the errbuf
return -1;
default:
{
SOCK_ASSERT("Internal error", 0);
return -1;
};
}
}
if (ntohl(header.plen) != 0) // the message has an unexpected size
{
if (sock_discard(fp->rmt_sockctrl, ntohl(header.plen), fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
return -1;
}
return 0;
}
/*!
\ingroup remote_pri_func
\brief Send a filter to a remote host.
This function is called when the user wants to set a filter.
In case we're capturing from the network, it sends the filter to the other peer.
This function is called automatically when the user calls the pcap_setfilter().
Parameters and return values are exactly the same of the pcap_setfilter().
*/
int pcap_setfilter_remote(pcap_t *fp, struct bpf_program *prog)
{
if (!fp->rmt_capstarted)
{
// copy filter into the pcap_t structure
if (install_bpf_program(fp, prog) == -1)
return -1;
return 0;
}
// we have to update a filter during run-time
if (pcap_updatefilter_remote(fp, prog) )
return -1;
return 0;
}
/*!
\ingroup remote_pri_func
\brief Update the current filter in order not to capture rpcap packets.
This function is called *only* when the user wants exclude RPCAP packets
related to the current session from the captured packets.
\return '0' if everything is fine, '-1' otherwise. The error message (if one)
is returned into the 'errbuf' field of the pcap_t structure.
*/
int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog)
{
int RetVal= 0;
// We do not want to capture our RPCAP traffic. So, let's update the filter
if (fp->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP)
{
struct sockaddr_storage saddr; // temp, needed to retrieve the network data port chosen on the local machine
socklen_t saddrlen; // temp, needed to retrieve the network data port chosen on the local machine
char myaddress[128];
char myctrlport[128];
char mydataport[128];
char peeraddress[128];
char peerctrlport[128];
char *newfilter;
const int newstringsize= 1024;
int currentfiltersize;
// Get the name/port of the other peer
saddrlen = sizeof(struct sockaddr_storage);
if (getpeername(fp->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1)
{
sock_geterror("getpeername(): ", fp->errbuf, PCAP_ERRBUF_SIZE);
return -1;
}
if (getnameinfo( (struct sockaddr *) &saddr, saddrlen, peeraddress,
sizeof(peeraddress), peerctrlport, sizeof(peerctrlport), NI_NUMERICHOST | NI_NUMERICSERV) )
{
sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -