📄 pcap-new.c
字号:
/*
* Copyright (c) 2002 - 2003
* NetGroup, Politecnico di Torino (Italy)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Politecnico di Torino nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <pcap-int.h> // for the details of the pcap_t structure
#include <pcap-remote.h>
#include <sockutils.h>
#include <errno.h> // for the errno variable
#include <stdlib.h> // for malloc(), free(), ...
#include <string.h> // for strstr, etc
/*
\brief Global variable; needed to keep the message due to an error that we want to discard.
This can happen, for instance, because we already have an error message and we want to keep
the first one.
*/
char fakeerrbuf[PCAP_ERRBUF_SIZE + 1];
//! Keeps a list of all the opened connections in the active mode.
extern struct activehosts *activeHosts;
/*!
\brief Keeps the main socket identifier when we want to accept a new remote connection (active mode only).
See the documentation of pcap_remoteact_accept() and pcap_remoteact_cleanup() for more details.
*/
SOCKET sockmain;
/****************************************************
* *
* Function bodies *
* *
****************************************************/
/*! \ingroup remote_func
\brief It creates a list of network devices that can be opened with pcap_open().
This function is a superset of the old 'pcap_findalldevs()', which is obsolete, and which
allows listing only the devices present on the local machine.
Vice versa, pcap_findalldevs_ex() allows listing the devices present on a remote
machine as well. Moreover, pcap_findalldevs_ex() is platform independent, since it
relies on the standard pcap_findalldevs() to get addresses on the local machine.
In case the function has to list the interfaces on a remote machine, it opens a new control
connection toward that machine, it retrieves the interfaces, and it drops the connection.
However, if this function detects that the remote machine is in 'active' mode,
the connection is not dropped (see the 'sockctrl' parameters for more details).
In the same way, if we're in active mode and the connection is already opened, it
uses the existing socket.
This function can rely on the pcap_createsrcstr() to create the string that keeps
the capture device according to the new syntax, and the pcap_parsesrcstr() for the
other way round.
\param host: a char* buffer that keeps the address of the remote host on which
we want to see the interface list.
It can be NULL: in this case the function queries the local host for the locally
installed interfaces. The address can be both numeric (e.g. '10.11.12.13', '1:2:3::4')
and literal (e.g. 'foo.bar.com').
\param auth: a pointer to a pcap_rmtauth structure. This pointer keeps the information
required to authenticate the RPCAP connection to the remote host.
This parameter is not meaningful in case of a query to the local host: in that case
it can be NULL.
\param sockctrl: Socket to be used for the control connection.
This parameter is meaningful only if the control connection is already open when the
pcap_findalldevs() is called. This can be the case in which the 'ative' mode is used,
in which the capturing machine opens a control connection toward the client in order
to bypass in-middle firewalls. In that case, the control connection is already open,
and we have to use this one instead of opening a new one.
In case this parameter is non-zero, the 'host' and 'port' parameters are meaningless:
the software will always try to retrieve the network adapters using this control
connection, despite the value assumed by 'host' and 'port'.
In case this parameter is non-zero, the socket is not closed at the end of the function
and it remains open for future use.
\param port: a char* buffer (e.g. "2003") that keeps the network port on which we
want to connect to.
It can be NULL: in this case the function uses the standard port, defined in
RPCAP_DEFAULT_NETPORT.
\param alldevs: a 'struct pcap_if_t' pointer, which will be properly allocated inside
this function. When the function returns, it is set to point to the first element
of the interface list; each element of the list is of type 'struct pcap_if_t'.
\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).
\return '0' if everything is fine, '-1' if some errors occurred. The list of the devices
is returned in the 'alldevs' variable.
When the function returns correctly, 'alldevs' cannot be NULL. In other words, this
function returns '-1' also in case the system does not have any interface to list.
The error message is returned in the 'errbuf' variable. An error could be due to
several reasons:
- libpcap/WinPcap was not installed on the local/remote host
- the user does not have enough privileges to list the devices
- a network problem
- the RPCAP version negotiation failed
- other errors (not enough memory and others).
\warning There may be network devices that cannot be opened with pcap_open() by the process
calling pcap_findalldevs(), because, for example, that process might not have
sufficient privileges to open them for capturing; if so, those devices will not
appear on the list.
\warning The interface list must be deallocated manually by using the pcap_freealldevs().
*/
int pcap_findalldevs_ex(char *host, char *port, SOCKET sockctrl, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
{
unsigned int nread= 0; // number of bytes of the payload read from the socket
struct addrinfo hints; // temp variable needed to resove hostnames into to socket representation
struct addrinfo *addrinfo; // temp variable needed to resove hostnames into to socket representation
struct rpcap_header header; // structure that keeps the general header of the rpcap protocol
int i,j; // temp variables
int naddr; // temp var needed to avoid problems with IPv6 addresses
int retval; // store the return value of the functions
int nif; // Number of interfaces listed
int active= 0; // 'true' if we the other end-party is in active mode
// We have to perform two controls here, because the user can call this function in two ways:
// pcap_findalldevs_ex(NULL, ...) ==> address == NULL
// pcap_findalldevs_ex("", ...) ==> address[0] == 0
if ( (host == NULL) || (host[0] == 0) )
{
// The user wants to retrieve adapters from a local host
if (pcap_findalldevs(alldevs, errbuf) == -1)
return -1;
if ( (alldevs == NULL) || (*alldevs == NULL) )
{
snprintf(errbuf, PCAP_ERRBUF_SIZE,
"No interfaces found! Make sure libpcap/WinPcap is properly installed"
" on the local machine.");
return -1;
}
return 0;
}
// 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) == -1)
return -1;
// Check for active mode
if ( (retval= rpcap_remoteact_getsock(host, errbuf)) == -1)
return -1;
if (retval)
{
sockctrl= retval;
active= 1;
}
else // we're not in active mode; let's opening a new control connection (if needed)
{
addrinfo= NULL;
memset(&hints, 0, sizeof(struct addrinfo) );
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ( (port == NULL) || (port[0] == 0) )
{
// the user chose not to specify the port
if (sock_validaddr(host, RPCAP_DEFAULT_NETPORT, &hints, &addrinfo, errbuf) == -1)
return -1;
}
else
{
if (sock_validaddr(host, port, &hints, &addrinfo, errbuf) == -1)
return -1;
}
if ( (sockctrl= sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf)) == -1)
goto error;
// addrinfo is no longer used
freeaddrinfo(addrinfo);
addrinfo= NULL;
if ( rpcap_sendauth(sockctrl, auth, errbuf) == -1)
{
// Control connection has to be closed only in case the remote machine is in passive mode
if (!active)
sock_close(sockctrl, fakeerrbuf);
return -1;
}
}
// RPCAP findalldevs command
rpcap_createhdr(&header, RPCAP_MSG_FINDALLIF_REQ, 0, 0);
if ( sock_send(sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf) == -1 )
goto error;
if ( sock_recv(sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf) == -1)
goto error;
// Checks if the message is correct
retval= rpcap_checkmsg(errbuf, sockctrl, &header, RPCAP_MSG_FINDALLIF_REPLY, RPCAP_MSG_ERROR, 0);
if (retval != RPCAP_MSG_FINDALLIF_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
break;
case RPCAP_MSG_ERROR: // The other endpoint reported an error
break;
default:
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Internal error");
break;
};
}
if (!active)
sock_close(sockctrl, fakeerrbuf);
return -1;
}
// read the number of interfaces
nif= ntohs(header.value);
// loop until all interfaces have been received
for (i= 0; i < nif; i++)
{
struct rpcap_findalldevs_if findalldevs_if;
pcap_if_t *dev; // Previous device into the pcap_if_t chain
// receive the findalldevs structure from remote hsot
if ( (nread+= sock_recv(sockctrl, (char *) &findalldevs_if,
sizeof(struct rpcap_findalldevs_if), errbuf) ) == -1)
goto error;
findalldevs_if.namelen= ntohs(findalldevs_if.namelen);
findalldevs_if.desclen= ntohs(findalldevs_if.desclen);
findalldevs_if.naddr= ntohs(findalldevs_if.naddr);
// allocate the main structure
if (i == 0)
{
(*alldevs)= (pcap_if_t *) malloc(sizeof(pcap_if_t) );
dev= (*alldevs);
}
else
{
dev->next= (pcap_if_t *) malloc(sizeof(pcap_if_t) );
dev= dev->next;
}
// check that the malloc() didn't fail
if (dev == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
goto error;
}
dev->next= NULL;
dev->addresses= NULL;
// allocate mem for name and description
if (findalldevs_if.namelen)
{
dev->name= (char *) malloc(findalldevs_if.namelen + 1);
if (dev->name == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
goto error;
}
// Retrieve adapter name and description
if ( (nread+= sock_recv(sockctrl, dev->name, findalldevs_if.namelen, errbuf) ) == -1)
goto error;
dev->name[findalldevs_if.namelen]= 0;
}
else
dev->name= NULL;
if (findalldevs_if.desclen)
{
dev->description= (char *) malloc(findalldevs_if.desclen + 1);
if (dev->description == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
goto error;
}
// Retrieve adapter name and description
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -