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

📄 pcap-remote.c

📁 Windows XP下的抓包程序实现
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -