📄 daemon.c
字号:
// Now we have to create a new socket to send packets
if (serveropen_dp) // Data connection is opened by the server toward the client
{
sprintf(portdata, "%d", ntohs(startcapreq.portdata) );
// Get the name of the other peer (needed to connect to that specific network address)
if (getnameinfo( (struct sockaddr *) &saddr, saddrlen, peerhost,
sizeof(peerhost), NULL, 0, NI_NUMERICHOST) )
{
sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
goto error;
}
if (sock_validaddr(peerhost, portdata, &hints, &addrinfo, errbuf) == -1)
goto error;
if ( (sockdata= sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf)) == -1)
goto error;
}
else // Data connection is opened by the client toward the server
{
hints.ai_flags = AI_PASSIVE;
// Let's the server socket pick up a free network port for us
if (sock_validaddr(NULL, "0", &hints, &addrinfo, errbuf) == -1)
goto error;
if ( (sockdata= sock_open(addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, errbuf)) == -1)
goto error;
// 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(): ", 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(): ", errbuf, PCAP_ERRBUF_SIZE);
goto error;
}
}
// addrinfo is no longer used
freeaddrinfo(addrinfo);
addrinfo= NULL;
// save the socket ID for the next calls
fp->rmt_sockctrl= sockctrl; // Needed to send an error on the ctrl connection
// Now I can set the filter
if ( daemon_unpackapplyfilter(fp, &nread, &plen, errbuf) )
goto error;
// Now, I can send a RPCAP start capture reply message
if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf) == -1)
goto error;
rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_STARTCAP_REPLY, 0, sizeof(struct rpcap_startcapreply) );
startcapreply= (struct rpcap_startcapreply *) &sendbuf[sendbufidx];
if ( sock_bufferize(NULL, sizeof(struct rpcap_startcapreply), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf) == -1)
goto error;
memset(startcapreply, 0, sizeof(struct rpcap_startcapreply) );
startcapreply->bufsize= htonl(fp->bufsize);
if (!serveropen_dp)
{
sscanf(portdata, "%d", &(startcapreply->portdata) );
startcapreply->portdata= htons(startcapreply->portdata);
}
if ( sock_send(sockctrl, sendbuf, sendbufidx, errbuf) == -1)
goto error;
if (!serveropen_dp)
{
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(): ", errbuf, PCAP_ERRBUF_SIZE);
goto error;
}
// Now that I accepted the connection, the server socket is no longer needed
sock_close(sockdata, errbuf);
sockdata= socktemp;
}
fp->rmt_sockdata= sockdata;
// Now we have to create a new thread to receive packets
if ( pthread_create( &threaddata, NULL, (void *) &daemon_thrdatamain, (void *) fp) )
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread");
goto error;
}
fp->rmt_threaddata= threaddata;
// Check if all the data has been read; if not, discard the data in excess
if (nread != plen)
sock_discard(sockctrl, plen - nread, fakeerrbuf);
return fp;
error:
rpcap_senderror(sockctrl, errbuf, PCAP_ERR_STARTCAPTURE, fakeerrbuf);
if (addrinfo)
freeaddrinfo(addrinfo);
if (threaddata)
pthread_cancel(threaddata);
if (sockdata)
sock_close(sockdata, fakeerrbuf);
// Check if all the data has been read; if not, discard the data in excess
if (nread != plen)
sock_discard(sockctrl, plen - nread, fakeerrbuf);
if (fp)
{
pcap_close(fp);
fp= NULL;
}
return NULL;
}
int daemon_endcapture(pcap_t *fp, char *errbuf)
{
struct rpcap_header header;
SOCKET sockctrl;
if (fp->rmt_threaddata)
{
pthread_cancel(fp->rmt_threaddata);
fp->rmt_threaddata= 0;
}
if (fp->rmt_sockdata)
{
sock_close(fp->rmt_sockdata, fakeerrbuf);
fp->rmt_sockdata= 0;
}
sockctrl= fp->rmt_sockctrl;
pcap_close(fp);
fp= NULL;
rpcap_createhdr( &header, RPCAP_MSG_ENDCAP_REPLY, 0, 0);
if ( sock_send(sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf) == -1)
return -1;
return 0;
}
int daemon_unpackapplyfilter(pcap_t *fp, unsigned int *nread, int *plen, char *errbuf)
{
struct rpcap_filter filter;
struct rpcap_filterbpf_insn insn;
struct bpf_insn *bf_insn;
struct bpf_program bf_prog;
unsigned int i;
if ( ( *nread+= sock_recv(fp->rmt_sockctrl, (char *) &filter, sizeof(struct rpcap_filter), errbuf)) == -1)
{
// to avoid blocking on the sock_discard()
*plen= *nread;
return -1;
}
bf_prog.bf_len= ntohl(filter.nitems);
if (ntohs(filter.filtertype) != RPCAP_UPDATEFILTER_BPF)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported");
return -1;
}
bf_insn= (struct bpf_insn *) malloc ( sizeof(struct bpf_insn) * bf_prog.bf_len);
if (bf_insn == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
return -1;
}
bf_prog.bf_insns= bf_insn;
for (i= 0; i < bf_prog.bf_len; i++)
{
if ( ( *nread+= sock_recv(fp->rmt_sockctrl, (char *) &insn, sizeof(struct rpcap_filterbpf_insn), errbuf)) == -1)
return -1;
bf_insn->code= ntohs(insn.code);
bf_insn->jf= insn.jf;
bf_insn->jt= insn.jt;
bf_insn->k= ntohl(insn.k);
bf_insn++;
}
if (bpf_validate(bf_prog.bf_insns, bf_prog.bf_len) == 0)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions");
return -1;
}
if (pcap_setfilter(fp, &bf_prog) )
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", fp->errbuf);
return -1;
}
return 0;
}
int daemon_updatefilter(pcap_t *fp, uint32 plen)
{
struct rpcap_header header; // keeps the answer to the updatefilter command
unsigned int nread;
if ( daemon_unpackapplyfilter(fp, &nread, &plen, fp->errbuf) )
goto error;
// Check if all the data has been read; if not, discard the data in excess
if (nread != plen)
{
if (sock_discard(fp->rmt_sockctrl, plen - nread, fakeerrbuf) )
{
nread= plen; // just to avoid to call discard again in the 'error' section
goto error;
}
}
// A response is needed, otherwise the other host does not know that everything went well
rpcap_createhdr( &header, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0);
if ( sock_send(fp->rmt_sockctrl, (char *) &header, sizeof (struct rpcap_header), fp->errbuf) )
goto error;
return 0;
error:
if (nread != plen)
sock_discard(fp->rmt_sockctrl, plen - nread, fakeerrbuf);
rpcap_senderror(fp->rmt_sockctrl, fp->errbuf, PCAP_ERR_UPDATEFILTER, fakeerrbuf);
return -1;
}
int daemon_getstats(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
struct pcap_stat stats; // local statistics
struct rpcap_stats *netstats; // statistics sent on the network
if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf) == -1)
goto error;
rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats));
netstats= (struct rpcap_stats *) &sendbuf[sendbufidx];
if ( sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf) == -1)
goto error;
if (pcap_stats(fp, &stats) )
goto error;
netstats->ifdrop= htonl(stats.ps_ifdrop);
netstats->ifrecv= htonl(stats.ps_recv);
netstats->krnldrop= htonl(stats.ps_drop);
netstats->svrcapt= htonl(fp->md.TotCapt);
// Send the packet
if ( sock_send(fp->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf) == -1)
goto error;
return 0;
error:
rpcap_senderror(fp->rmt_sockctrl, fp->errbuf, PCAP_ERR_GETSTATS, fakeerrbuf);
return -1;
}
int daemon_getstatsnopcap(SOCKET sockctrl, unsigned int ifdrops, unsigned int ifrecv,
unsigned int krnldrop, unsigned int svrcapt, char *errbuf)
{
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_stats *netstats; // statistics sent on the network
if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf) == -1)
goto error;
rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats));
netstats= (struct rpcap_stats *) &sendbuf[sendbufidx];
if ( sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf) == -1)
goto error;
netstats->ifdrop= htonl(ifdrops);
netstats->ifrecv= htonl(ifrecv);
netstats->krnldrop= htonl(krnldrop);
netstats->svrcapt= htonl(svrcapt);
// Send the packet
if ( sock_send(sockctrl, sendbuf, sendbufidx, errbuf) == -1)
goto error;
return 0;
error:
rpcap_senderror(sockctrl, errbuf, PCAP_ERR_GETSTATS, fakeerrbuf);
return -1;
}
void daemon_thrdatamain(void *ptr)
{
char errbuf[PCAP_ERRBUF_SIZE + 1]; // error buffer
pcap_t *fp; // pointer to a 'pcap' structure
int retval; // general variable used to keep the return value of other functions
struct rpcap_pkthdr *net_pkt_header;// header of the packet
struct pcap_pkthdr *pkt_header; // pointer to the buffer that contains the header of the current packet
u_char *pkt_data; // pointer to the buffer that contains the current packet
char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
int sendbufidx; // index which keeps the number of bytes currently buffered
fp= (pcap_t *) ptr;
fp->md.TotCapt= 0; // counter which is incremented each time a packet is received
// Initialize errbuf
memset(errbuf, 0, sizeof(errbuf) );
// Modify thread params so that it can be killed at any time
if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) )
goto error;
if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) )
goto error;
// Retrieve the packets
while ((retval = pcap_next_ex(fp, &pkt_header, &pkt_data)) >= 0)
{
if (retval == 0) // Read timeout elapsed
continue;
sendbufidx= 0;
// Bufferize the general header
if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf) == -1)
goto error;
rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_PACKET, 0,
(uint16) (sizeof(struct rpcap_pkthdr) + pkt_header->caplen) );
net_pkt_header= (struct rpcap_pkthdr *) &sendbuf[sendbufidx];
// Bufferize the pkt header
if ( sock_bufferize(NULL, sizeof(struct rpcap_pkthdr), NULL, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf) == -1)
goto error;
net_pkt_header->caplen= htonl(pkt_header->caplen);
net_pkt_header->len= htonl(pkt_header->len);
net_pkt_header->npkt= htonl( ++(fp->md.TotCapt) );
net_pkt_header->timestamp_sec= htonl(pkt_header->ts.tv_sec);
net_pkt_header->timestamp_usec= htonl(pkt_header->ts.tv_usec);
// Bufferize the pkt data
if ( sock_bufferize((char *) pkt_data, pkt_header->caplen, sendbuf, &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf) == -1)
goto error;
// Send the packet
if ( sock_send(fp->rmt_sockdata, sendbuf, sendbufidx, errbuf) == -1)
goto error;
}
if (retval == -1)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(fp) );
rpcap_senderror(fp->rmt_sockctrl, errbuf, PCAP_ERR_READEX, fakeerrbuf);
goto error;
}
error:
SOCK_ASSERT(errbuf, 1);
closesocket(fp->rmt_sockdata);
fp->rmt_sockdata= 0;
fp->rmt_threaddata= 0;
return;
}
/*!
\brief It serializes a network address.
It accepts a 'sockaddr_storage' structure as input, and it converts it appropriately into a format
that can be used to be sent on the network. Basically, it applies all the hton()
conversion required to the input variable.
\param sockaddrin: a 'sockaddr_storage' pointer to the variable that has to be
serialized. This variable can be both a 'sockaddr_in' and 'sockaddr_in6'.
\param sockaddrout: a 'sockaddr_storage' pointer to the variable that will contain
the serialized data. This variable has to be allocated by the user.
\return None
\warning This function supports only AF_INET and AF_INET6 address families.
*/
void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct sockaddr_storage *sockaddrout)
{
memset(sockaddrout, 0, sizeof(struct sockaddr_storage) );
// There can be the case in which the sockaddrin is not available
if (sockaddrin == NULL) return;
// Warning: we support only AF_INET and AF_INET6
if (sockaddrin->ss_family == AF_INET)
{
struct sockaddr_in *sockaddr;
sockaddr= (struct sockaddr_in *) sockaddrin;
sockaddr->sin_family= htons(sockaddr->sin_family);
sockaddr->sin_port= htons(sockaddr->sin_port);
memcpy(sockaddrout, sockaddr, sizeof(struct sockaddr_in) );
}
else
{
struct sockaddr_in6 *sockaddr;
sockaddr= (struct sockaddr_in6 *) sockaddrin;
sockaddr->sin6_family= htons(sockaddr->sin6_family);
sockaddr->sin6_port= htons(sockaddr->sin6_port);
sockaddr->sin6_flowinfo= htonl(sockaddr->sin6_flowinfo);
sockaddr->sin6_scope_id= htonl(sockaddr->sin6_scope_id);
memcpy(sockaddrout, sockaddr, sizeof(struct sockaddr_in6) );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -