📄 pcap-remote.c
字号:
(*callback)(user, pkt_header, pkt_data);
n++;
}
else
return n;
}
return n;
}
/*! \ingroup remote_pri_func
\brief It sends a CLOSE command to the capture server.
This function is called when the user wants to close a pcap_t adapter.
In case we're capturing from the network, it sends a command to the other
peer that says 'ok, let's stop capturing'.
This function is called automatically when the user calls the pcap_close().
Parameters and return values are exactly the same of the pcap_close().
\warning Since we're closing the connection, we do not check for errors.
*/
void pcap_close_remote(pcap_t *fp)
{
struct rpcap_header header; // header of the RPCAP packet
struct activehosts *temp; // temp var needed to scan the host list chain, to detect if we're in active mode
int active= 0; // active mode or not?
// detect if we're in active mode
temp= activeHosts;
while (temp)
{
if (temp->sockctrl == fp->rmt_sockctrl)
{
active= 1;
break;
}
temp= temp->next;
}
if (!active)
{
rpcap_createhdr( &header, RPCAP_MSG_CLOSE, 0, 0);
// I don't check for errors, since I'm going to close everything
sock_send(fp->rmt_sockctrl, (char *) &header, sizeof (struct rpcap_header), NULL, 0);
}
else
{
rpcap_createhdr( &header, RPCAP_MSG_ENDCAP_REQ, 0, 0);
// I don't check for errors, since I'm going to close everything
sock_send(fp->rmt_sockctrl, (char *) &header, sizeof (struct rpcap_header), NULL, 0);
// wait for the answer
// Don't check what we got, since the present libpcap does not uses this pcap_t anymore
sock_recv(fp->rmt_sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, NULL, 0);
if ( ntohl(header.plen) != 0)
sock_discard(fp->rmt_sockctrl, ntohl(header.plen), NULL, 0);
}
if (fp->rmt_sockdata)
{
sock_close(fp->rmt_sockdata, NULL, 0);
fp->rmt_sockdata= 0;
}
if ( (!active) && (fp->rmt_sockctrl) )
sock_close(fp->rmt_sockctrl, NULL, 0);
fp->rmt_sockctrl= 0;
if (fp->currentfilter)
{
free(fp->currentfilter);
fp->currentfilter= NULL;
}
// To avoid inconsistencies in the number of sock_init()
sock_cleanup();
}
/*! \ingroup remote_pri_func
\brief It retrieves network statistics from the other peer.
This function is just a void cointainer, since the work is done by the rpcap_stats_remote().
See that funcion for more details.
Parameters and return values are exactly the same of the pcap_stats().
*/
int pcap_stats_remote(pcap_t *p, struct pcap_stat *ps)
{
struct pcap_stat *retval;
retval= rpcap_stats_remote(p, ps, PCAP_STATS_STANDARD);
if (retval)
return 0;
else
return -1;
}
/*! \ingroup remote_pri_func
\brief It retrieves network statistics from the other peer.
This function is just a void cointainer, since the work is done by the rpcap_stats_remote().
See that funcion for more details.
Parameters and return values are exactly the same of the pcap_stats_ex().
*/
struct pcap_stat *pcap_stats_ex_remote(pcap_t *p)
{
// '0' (third param) means 'standard pcap_stats()'
return (rpcap_stats_remote(p, &(p->md.stat), PCAP_STATS_EX));
}
/*! \ingroup remote_pri_func
\brief It retrieves network statistics from the other peer.
This function can be called in two modes:
- PCAP_STATS_STANDARD: if we want just standard statistics (i.e. the pcap_stats() )
- PCAP_STATS_EX: if we want extended statistics (i.e. the pcap_stats_ex() )
This 'mode' parameter is needed because in the standard pcap_stats() the variable that keeps the
statistics is allocated by the user. Unfortunately, this structure has been extended in order
to keep new stats. However, if the user has a smaller structure and it passes it to the pcap_stats,
thid function will try to fill in more data than the size of the structure, so that the application
goes in memory overflow.
So, we need to know it we have to copy just the standard fields, or the extended fields as well.
In case we want to copy the extended fields as well, the problem of memory overflow does no
longer exist because the structure pcap_stat is no longer allocated by the program;
it is allocated by the library instead.
\param p: the pcap_t structure related to the current instance.
\param ps: a 'pcap_stat' structure, needed for compatibility with pcap_stat(), in which
the structure is allocated by the user. In case of pcap_stats_ex, this structure and the
function return value point to the same variable.
\param mode: one of PCAP_STATS_STANDARD or PCAP_STATS_EX.
\return The structure that keeps the statistics, or NULL in case of error.
The error string is placed in the pcap_t structure.
*/
struct pcap_stat *rpcap_stats_remote(pcap_t *p, struct pcap_stat *ps, int mode)
{
struct rpcap_header header; // header of the RPCAP packet
struct rpcap_stats netstats; // statistics sent on the network
unsigned int nread= 0; // number of bytes of the payload read from the socket
int retval; // temp variable which stores functions return value
// If the capture has still to start, we cannot ask statistics to the other peer
// So, we return a fake number
if (!p->rmt_capstarted)
{
if (mode == PCAP_STATS_STANDARD)
{
ps->ps_drop= 0;
ps->ps_ifdrop= 0;
ps->ps_recv= 0;
}
else
{
ps->ps_capt= 0;
ps->ps_drop= 0;
ps->ps_ifdrop= 0;
ps->ps_netdrop= 0;
ps->ps_recv= 0;
ps->ps_sent= 0;
}
return ps;
}
rpcap_createhdr(&header, RPCAP_MSG_STATS_REQ, 0, 0);
// Send the PCAP_STATS command
if (sock_send(p->rmt_sockctrl, (char *) &header, sizeof (struct rpcap_header), p->errbuf, PCAP_ERRBUF_SIZE) )
goto error;
// Receive the RPCAP stats reply message
if (sock_recv(p->rmt_sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, p->errbuf, PCAP_ERRBUF_SIZE) == -1)
goto error;
// Checks if the message is correct
retval= rpcap_checkmsg(p->errbuf, p->rmt_sockctrl, &header, RPCAP_MSG_STATS_REPLY, RPCAP_MSG_ERROR, 0);
if (retval != RPCAP_MSG_STATS_REPLY) // the message is not the one expected
{
switch (retval)
{
case -3: // Unrecoverable network error
case -2: // The other endpoint send a message that is not allowed here
case -1: // The other endpoint has a version number that is not compatible with our
goto error;
case RPCAP_MSG_ERROR: // The other endpoint reported an error
// Update nread, since the rpcap_checkmsg() already purged the buffer
nread = ntohl(header.plen);
// Do nothing; just exit; the error code is already into the errbuf
goto error;
default:
{
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Internal error");
goto error;
};
}
}
if ( (nread= sock_recv(p->rmt_sockctrl, (char *) &netstats, sizeof(struct rpcap_stats), SOCK_RECEIVEALL_YES, p->errbuf, PCAP_ERRBUF_SIZE)) == -1)
goto error;
if (mode == PCAP_STATS_STANDARD)
{
ps->ps_drop= ntohl(netstats.krnldrop);
ps->ps_ifdrop= ntohl(netstats.ifdrop);
ps->ps_recv= ntohl(netstats.ifrecv);
}
else
{
ps->ps_capt= p->md.TotCapt;
ps->ps_drop= ntohl(netstats.krnldrop);
ps->ps_ifdrop= ntohl(netstats.ifdrop);
ps->ps_netdrop= p->md.TotNetDrops;
ps->ps_recv= ntohl(netstats.ifrecv);
ps->ps_sent= ntohl(netstats.svrcapt);
}
// Checks if all the data has been read; if not, discard the data in excess
if (nread != ntohl(header.plen))
{
if (sock_discard(p->rmt_sockctrl, ntohl(header.plen) - nread, NULL, 0) == 1)
goto error;
}
return ps;
error:
if (nread != ntohl(header.plen))
sock_discard(p->rmt_sockctrl, ntohl(header.plen) - nread, NULL, 0);
return NULL;
}
/*! \ingroup remote_pri_func
\brief It opens a remote adapter by opening an RPCAP connection and so on.
This function does basically the job of pcap_open_live() for a remote interface.
In other words, we have a pcap_read for win32, which reads packets from NPF,
another for LINUX, and so on. Now, we have a pcap_opensource_remote() as well.
The difference, here, is the capture thread does not start until the
pcap_startcapture_remote() is called.
This is because, in remote capture, we cannot start capturing data as soon ad the
'open adapter' command is sent. Suppose the remote adapter is already overloaded;
if we start a capture (which, by default, has a NULL filter) the new traffic can
saturate the network.
Instead, we want to "open" the adapter, then send a "start capture" command only
when we're ready to start the capture.
This funtion does this job: it sends a "open adapter" command (according to the
RPCAP protocol), but it does not start the capture.
Since the other libpcap functions do not share this way of life, we have to make
some dirty things in order to make everyting working.
\param source: see pcap_open().
\param auth: see pcap_open().
\param errbuf: a pointer to a user-allocated buffer (of size PCAP_ERRBUF_SIZE)
that will contain the error message (in case there is one). It could be either a network problem,
an RPCAP problem (e.g. authentication failed), and more.
\return A pointer to a 'pcap_t' which can be used as a parameter to the following
calls (pcap_compile() and so on) and that specifies an opened WinPcap session. In case of
problems, it returns NULL and the 'errbuf' variable keeps the error message.
\warning In case we call the pcap_compile() and the capture is not started, the filter
will be saved into the pcap_t structure, and it will be sent to the other host later
(when the pcap_startcapture_remote() is called).
*/
pcap_t *pcap_opensource_remote(const char *source, struct pcap_rmtauth *auth, char *errbuf)
{
char host[PCAP_BUF_SIZE], ctrlport[PCAP_BUF_SIZE], iface[PCAP_BUF_SIZE];
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 pcap *fp= NULL; // pcap_t main variable
unsigned int nread= 0; // number of bytes of the payload read from the socket
int retval; // store the return value of the functions
int active= 0; // '1' if we're in active mode
// socket-related variables
struct addrinfo hints; // temp, needed to open a socket connection
struct addrinfo *addrinfo; // temp, needed to open a socket connection
SOCKET sockctrl= 0; // socket descriptor of the control connection
// RPCAP-related variables
struct rpcap_header header; // header of the RPCAP packet
struct rpcap_openreply openreply; // open reply message
// determine the type of the source (NULL, file, local, remote)
// You must have a valid source string even if we're in active mode, because otherwise
// the call to the following funciton will fail.
if (pcap_parsesrcstr(source, &retval, host, ctrlport, iface, errbuf) == -1)
return NULL;
if ( retval != PCAP_SRC_IFREMOTE)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "This function is able to open only remote interfaces");
return NULL;
}
addrinfo= NULL;
// Warning: this call can be the first one called by the user.
// For this reason, we have to initialize the WinSock support.
if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
return NULL;
retval= rpcap_remoteact_getsock(host, errbuf);
if (retval == -1)
return NULL;
// The capturing machine is in active mode
if (retval)
{
sockctrl= retval;
active= 1;
}
else
{
memset(&hints, 0, sizeof(struct addrinfo) );
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ( (ctrlport == NULL) || (ctrlport[0] == 0) )
{
// the user chose not to specify the port
if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
return NULL;
}
else
{
// the user chose not to specify the port
if (sock_initaddress(host, ctrlport, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
return NULL;
}
if ( (sockctrl= sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == -1)
goto error;
freeaddrinfo(addrinfo);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -