📄 pcap-remote.c
字号:
addrinfo= NULL;
if ( rpcap_sendauth(sockctrl, auth, errbuf) == -1)
goto error;
}
// Now it's time to start playing with the RPCAP protocol
// RPCAP open command: create the request message
if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) )
goto error;
rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_OPEN_REQ, 0, strlen(iface) );
if ( sock_bufferize(iface, strlen(iface), sendbuf, &sendbufidx,
RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) )
goto error;
if ( sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) )
goto error;
// Receive the RPCAP open reply message
if (sock_recv(sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1)
goto error;
// Checks if the message is correct
retval= rpcap_checkmsg(errbuf, sockctrl, &header, RPCAP_MSG_OPEN_REPLY, RPCAP_MSG_ERROR, 0);
if (retval != RPCAP_MSG_OPEN_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(errbuf, PCAP_ERRBUF_SIZE, "Internal error");
goto error;
};
}
}
if ( (nread+= sock_recv(sockctrl, (char *) &openreply, sizeof(struct rpcap_openreply), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1)
goto error;
// Allocates a pcap_t struct for this end of the connection
fp = (pcap_t *) malloc( sizeof(pcap_t) );
if (fp == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
goto error;
}
memset(fp, 0, sizeof(pcap_t));
// Set proper fields into the pcap_t struct
fp->linktype= ntohl(openreply.linktype);
fp->tzoff= ntohl(openreply.tzoff);
fp->rmt_sockctrl= sockctrl;
fp->rmt_clientside= 1;
// This code is duplicated from the end of this function
fp->read_op= pcap_read_remote;
fp->setfilter_op= pcap_setfilter_remote;
fp->getnonblock_op= NULL; // This is not implemented in remote capture
fp->setnonblock_op= NULL; // This is not implemented in remote capture
fp->stats_op= pcap_stats_remote;
fp->close_op= pcap_close_remote;
// Checks if all the data has been read; if not, discard the data in excess
if (nread != ntohl(header.plen))
{
if (sock_discard(sockctrl, ntohl(header.plen) - nread, NULL, 0) == 1)
goto error;
}
return fp;
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(sockctrl, ntohl(header.plen) - nread, NULL, 0);
if (addrinfo)
freeaddrinfo(addrinfo);
if (!active)
sock_close(sockctrl, NULL, 0);
if (fp)
{
pcap_close(fp);
fp= NULL;
}
return NULL;
}
/*! \ingroup remote_pri_func
\brief It starts a remote capture.
This function is requires since the RPCAP protocol decouples the 'open' from the
'start capture' functions.
This function takes all the parameters needed (which have been stored into the pcap_t structure)
and sends them to the server.
If everything is fine, it creates a new child thread that reads data from the network
and puts data it into the user buffer.
The pcap_read() will read data from the user buffer, as usual.
The remote capture acts like a new "kernel", which puts packets directly into
the buffer pointed by pcap_t.
In fact, this function does not rely on a kernel that reads packets and put them
into the user buffer; it has to do that on its own.
\param fp: the pcap_t descriptor of the device currently open.
\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_startcapture_remote(pcap_t *fp)
{
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
char portdata[PCAP_BUF_SIZE]; // temp variable needed to keep the network port for the the data connection
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
struct activehosts *temp; // temp var needed to scan the host list chain, to detect if we're in active mode
char host[INET6_ADDRSTRLEN + 1]; // numeric name of the other host
// socket-related variables
struct addrinfo hints; // temp, needed to open a socket connection
struct addrinfo *addrinfo; // temp, needed to open a socket connection
SOCKET sockdata= 0; // socket descriptor of the data connection
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
int ai_family; // temp, keeps the address family used by the control connection
// RPCAP-related variables
struct rpcap_header header; // header of the RPCAP packet
struct rpcap_startcapreq *startcapreq; // start capture request message
struct rpcap_startcapreply startcapreply; // start capture reply message
// Variables related to the buffer setting
int res, itemp;
int sockbufsize= 0;
// Let's check if sampling has been required.
// If so, let's set it first
if (pcap_setsampling_remote(fp) != 0)
return -1;
// detect if we're in active mode
temp= activeHosts;
while (temp)
{
if (temp->sockctrl == fp->rmt_sockctrl)
{
active= 1;
break;
}
temp= temp->next;
}
addrinfo= NULL;
// Gets the complete sockaddr structure used in the ctrl connection
// This is needed to get the address family of the control socket
// Tip: I cannot save the ai_family of the ctrl sock in the pcap_t struct,
// since the ctrl socket can already be open in case of active mode;
// so I would have to call getpeername() anyway
saddrlen = sizeof(struct sockaddr_storage);
if (getpeername(fp->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1)
{
sock_geterror("getsockname(): ", fp->errbuf, PCAP_ERRBUF_SIZE);
goto error;
}
ai_family= ((struct sockaddr_storage *) &saddr)->ss_family;
// Get the numeric address of the remote host we are connected to
if (getnameinfo( (struct sockaddr *) &saddr, saddrlen, host,
sizeof(host), NULL, 0, NI_NUMERICHOST) )
{
sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE);
goto error;
}
/*
Data connection is opened by the server toward the client if:
- we're using TCP, and the user wants us to be in active mode
- we're using UDP
*/
if ( (active) || (fp->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) )
{
// We have to create a new socket to receive packets
// We have to do that immediately, since we have to tell the other
// end which network port we picked up
memset(&hints, 0, sizeof(struct addrinfo) );
// TEMP addrinfo is NULL in case of active
hints.ai_family = ai_family; // Use the same address family of the control socket
hints.ai_socktype = (fp->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // Data connection is opened by the server toward the client
// Let's the server pick up a free network port for us
if (sock_initaddress(NULL, "0", &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
goto error;
if ( (sockdata= sock_open(addrinfo, SOCKOPEN_SERVER,
1 /* max 1 connection in queue */, fp->errbuf, PCAP_ERRBUF_SIZE)) == -1)
goto error;
// addrinfo is no longer used
freeaddrinfo(addrinfo);
addrinfo= NULL;
// get the complete sockaddr structure used in the data connection
saddrlen = sizeof(struct sockaddr_storage);
if (getsockname(sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1)
{
sock_geterror("getsockname(): ", fp->errbuf, PCAP_ERRBUF_SIZE);
goto error;
}
// Get the local port the system picked up
if (getnameinfo( (struct sockaddr *) &saddr, saddrlen, NULL,
0, portdata, sizeof(portdata), NI_NUMERICSERV) )
{
sock_geterror("getnameinfo(): ", fp->errbuf, PCAP_ERRBUF_SIZE);
goto error;
}
}
// Now it's time to start playing with the RPCAP protocol
// RPCAP start ca[ture command: create the request message
if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE) )
goto error;
rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_STARTCAP_REQ, 0,
sizeof(struct rpcap_startcapreq) + sizeof(struct rpcap_filter) + fp->fcode.bf_len * sizeof(struct rpcap_filterbpf_insn) );
// Fill the structure needed to open an adapter remotely
startcapreq= (struct rpcap_startcapreq *) &sendbuf[sendbufidx];
if ( sock_bufferize(NULL, sizeof(struct rpcap_startcapreq), NULL,
&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE) )
goto error;
memset(startcapreq, 0, sizeof(struct rpcap_startcapreq) );
// By default, apply half the timeout on one side, half of the other
#ifdef linux
fp->md.timeout= fp->md.timeout/2;
startcapreq->read_timeout= htonl(fp->md.timeout);
#else
fp->timeout= fp->timeout/2;
startcapreq->read_timeout= htonl(fp->timeout);
#endif
// portdata on the openreq is meaningful only if we're in active mode
if ( (active) || (fp->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) )
{
sscanf(portdata, "%d", (int *) &(startcapreq->portdata)); // cast to avoid a compiler warning
startcapreq->portdata= htons(startcapreq->portdata);
}
startcapreq->snaplen= htonl(fp->snapshot);
startcapreq->flags= 0;
if (fp->rmt_flags & PCAP_OPENFLAG_PROMISCUOUS)
startcapreq->flags|= RPCAP_STARTCAPREQ_FLAG_PROMISC;
if (fp->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)
startcapreq->flags|= RPCAP_STARTCAPREQ_FLAG_DGRAM;
if (active)
startcapreq->flags|= RPCAP_STARTCAPREQ_FLAG_SERVEROPEN;
startcapreq->flags= htons(startcapreq->flags);
// Pack the capture filter
if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, &fp->fcode) )
goto error;
if ( sock_send(fp->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf, PCAP_ERRBUF_SIZE) )
goto error;
// Receive the RPCAP start capture reply message
if (sock_recv(fp->rmt_sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
goto error;
// Checks if the message is correct
retval= rpcap_checkmsg(fp->errbuf, fp->rmt_sockctrl, &header, RPCAP_MSG_STARTCAP_REPLY, RPCAP_MSG_ERROR, 0);
if (retval != RPCAP_MSG_STARTCAP_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(fp->errbuf, PCAP_ERRBUF_SIZE, "Internal error");
goto error;
};
}
}
if ( (nread+= sock_recv(fp->rmt_sockctrl, (char *) &startcapreply,
sizeof(struct rpcap_startcapreply), SOCK_RECEIVEALL_YES, fp->errbuf, PCAP_ERRBUF_SIZE)) == -1)
goto error;
// In case of UDP data stream, the connection is always opened by the daemon
// So, this case is already covered by the code above.
// Now, we have still to handle TCP connections, because:
// - if we're in active mode, we have to wait for a remote connection
// - if we're in passive more, we have to start a connection
//
// We have to do he job in two steps because in case we're opening a tcp connection, we have
// to tell the port we're using to the remote side; in case we're accepting a TCP
// connection, we have to wait this info from the remote side.
if (!(fp->rmt_flags & PCAP_OPENFLAG_DATATX_UDP))
{
if (!active)
{
memset(&hints, 0, sizeof(struct addrinfo) );
hints.ai_family = ai_family; // Use the same address family of the control socket
hints.ai_socktype = (fp->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM;
sprintf(portdata, "%d", ntohs(startcapreply.portdata) );
// Let's the server pick up a free network port for us
if (sock_initaddress(host, portdata, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
goto error;
if ( (sockdata= sock_open(addrinfo, SOCKOPEN_CLIENT, 0, fp->errbuf, PCAP_ERRBUF_SIZE)) == -1)
goto error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -