⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 daemon.c

📁 用来监视网络通信数据的源代码和应用程序,方便网络程序底层开发.
💻 C
📖 第 1 页 / 共 3 页
字号:

	// 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 + -