📄 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
#ifndef WIN32
#include <dirent.h> // for readdir
#endif
//! 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;
//! String identifier to be used in the pcap_findalldevs_ex()
#define PCAP_TEXT_SOURCE_FILE "File"
//! String identifier to be used in the pcap_findalldevs_ex()
#define PCAP_TEXT_SOURCE_ADAPTER "Network adapter"
//! String identifier to be used in the pcap_findalldevs_ex()
#define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host"
//! String identifier to be used in the pcap_findalldevs_ex()
#define PCAP_TEXT_SOURCE_ON_REMOTE_HOST "on remote node"
/****************************************************
* *
* Function bodies *
* *
****************************************************/
int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
{
SOCKET sockctrl; // socket descriptor of the control connection
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
char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE], name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE];
int type;
pcap_t *fp;
char tmpstring[PCAP_BUF_SIZE + 1]; // Needed to convert names and descriptions from 'old' syntax to the 'new' one
pcap_if_t *dev; // Previous device into the pcap_if_t chain
if (strlen(source) > PCAP_BUF_SIZE)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
return -1;
}
// Determine the type of the source (file, local, remote)
// There are some differences if pcap_findalldevs_ex() is called to list files and remote adapters.
// In the first case, the name of the directory we have to look into must be present (therefore
// the 'name' parameter of the pcap_parsesrcstr() is present).
// In the second case, the name of the adapter is not required (we need just the host). So, we have
// to use a first time this function to get the source type, and a second time to get the appropriate
// info, which depends on the source type.
if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
return -1;
if (type == PCAP_SRC_IFLOCAL)
{
if (pcap_parsesrcstr(source, &type, host, NULL, NULL, errbuf) == -1)
return -1;
// Initialize temporary string
tmpstring[PCAP_BUF_SIZE]= 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;
}
// Scan all the interfaces and modify name and description
// This is a trick in order to avoid the re-implementation of the pcap_findalldevs here
dev= *alldevs;
while (dev)
{
// Create the new device identifier
if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1)
return -1;
// Delete the old pointer
free(dev->name);
dev->name= (char *) malloc( strlen(tmpstring) + 1);
if (dev->name == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
return -1;
}
// Copy the new device identifier into the correct memory location
strncpy(dev->name, tmpstring, strlen(tmpstring) + 1);
// Create the new device description
if ( (dev->description == NULL) || (dev->description[0] == 0) )
snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER,
dev->name, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
else
snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER,
dev->description, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
// Delete the old pointer
free(dev->description);
dev->description= (char *) malloc( strlen(tmpstring) + 1);
if (dev->description == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
return -1;
}
// Copy the new device description into the correct memory location
strncpy(dev->description, tmpstring, strlen(tmpstring) + 1);
dev= dev->next;
}
return 0;
}
(*alldevs)= NULL;
if (type == PCAP_SRC_FILE)
{
int stringlen;
#ifdef WIN32
WIN32_FIND_DATA filedata;
HANDLE filehandle;
#else
struct dirent *filedata;
DIR *unixdir;
#endif
if (pcap_parsesrcstr(source, &type, host, port, name, errbuf) == -1)
return -1;
// Check that the filename is correct
stringlen= strlen(name);
// The directory must end with '\' in Win32 and '/' in UNIX
#ifdef WIN32
#define ENDING_CHAR '\\'
#else
#define ENDING_CHAR '/'
#endif
if (name[stringlen - 1] != ENDING_CHAR )
{
name[stringlen]= ENDING_CHAR;
name[stringlen + 1]= 0;
stringlen++;
}
// Save the path for future reference
snprintf(path, sizeof(path), "%s", name);
#ifdef WIN32
// To perform directory listing, Win32 must have an 'asterisk' as ending char
if (name[stringlen - 1] != '*' )
{
name[stringlen]= '*';
name[stringlen + 1]= 0;
}
filehandle = FindFirstFile(name, &filedata);
if (filehandle == INVALID_HANDLE_VALUE)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
return -1;
}
#else
// opening the folder
unixdir= opendir(path);
// get the first file into it
filedata= readdir(unixdir);
if (filedata == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
return -1;
}
#endif
do
{
#ifdef WIN32
snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
#else
snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
#endif
fp= pcap_open_offline(filename, errbuf);
if (fp)
{
// allocate the main structure
if (*alldevs == NULL) // This is in case it is the first file
{
(*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));
return -1;
}
// Initialize the structure to 'zero'
memset(dev, 0, sizeof(pcap_if_t) );
// Create the new source identifier
if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1)
return -1;
stringlen= strlen(tmpstring);
dev->name= (char *) malloc(stringlen + 1);
if (dev->name == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
return -1;
}
strncpy(dev->name, tmpstring, stringlen);
dev->name[stringlen]= 0;
// Create the description
snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_FILE,
filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
stringlen= strlen(tmpstring);
dev->description= (char *) malloc(stringlen + 1);
if (dev->description == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
return -1;
}
// Copy the new device description into the correct memory location
strncpy(dev->description, tmpstring, stringlen + 1);
pcap_close(fp);
}
}
#ifdef WIN32
while (FindNextFile(filehandle, &filedata) != 0);
#else
while ( (filedata= readdir(unixdir)) != NULL);
#endif
#ifdef WIN32
// Close the search handle.
FindClose(filehandle);
#endif
return 0;
}
// If we come here, it is a remote host
// Retrieve the needed data for getting adapter list
if (pcap_parsesrcstr(source, &type, host, port, NULL, errbuf) == -1)
return -1;
// 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, PCAP_ERRBUF_SIZE) == -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_initaddress(host, RPCAP_DEFAULT_NETPORT, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
return -1;
}
else
{
if (sock_initaddress(host, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
return -1;
}
if ( (sockctrl= sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == -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, NULL, 0);
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, PCAP_ERRBUF_SIZE) == -1 )
goto error;
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_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -