📄 pcap-new.c
字号:
#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
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, NULL, 0);
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;
char tmpstring2[PCAP_BUF_SIZE + 1]; // Needed to convert names and descriptions from 'old' syntax to the 'new' one
int stringlen;
tmpstring2[PCAP_BUF_SIZE]= 0;
// receive the findalldevs structure from remote hsot
if ( (nread+= sock_recv(sockctrl, (char *) &findalldevs_if,
sizeof(struct rpcap_findalldevs_if), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) ) == -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;
}
// Initialize the structure to 'zero'
memset(dev, 0, sizeof(pcap_if_t) );
// allocate mem for name and description
if (findalldevs_if.namelen)
{
if (findalldevs_if.namelen >= sizeof(tmpstring) )
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface name too long");
goto error;
}
// Retrieve adapter name
if ( (nread+= sock_recv(sockctrl, tmpstring, findalldevs_if.namelen, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) ) == -1)
goto error;
tmpstring[findalldevs_if.namelen]= 0;
// Create the new device identifier
if (pcap_createsrcstr(tmpstring2, PCAP_SRC_IFREMOTE, host, port, tmpstring, errbuf) == -1)
return -1;
stringlen= strlen(tmpstring2);
dev->name= (char *) malloc(stringlen + 1);
if (dev->name == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
goto error;
}
// Copy the new device name into the correct memory location
strncpy(dev->name, tmpstring2, stringlen + 1);
}
if (findalldevs_if.desclen)
{
if (findalldevs_if.desclen >= sizeof(tmpstring) )
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface description too long");
goto error;
}
// Retrieve adapter description
if ( (nread+= sock_recv(sockctrl, tmpstring, findalldevs_if.desclen, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) ) == -1)
goto error;
tmpstring[findalldevs_if.desclen]= 0;
snprintf(tmpstring2, sizeof(tmpstring2) - 1, "%s '%s' %s %s", PCAP_TEXT_SOURCE_ADAPTER,
tmpstring, PCAP_TEXT_SOURCE_ON_REMOTE_HOST, host);
stringlen= strlen(tmpstring2);
dev->description= (char *) malloc(stringlen + 1);
if (dev->description == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
goto error;
}
// Copy the new device description into the correct memory location
strncpy(dev->description, tmpstring2, stringlen + 1);
}
dev->flags= ntohl(findalldevs_if.flags);
naddr= 0;
// loop until all addresses have been received
for (j= 0; j < findalldevs_if.naddr; j++)
{
struct rpcap_findalldevs_ifaddr ifaddr;
// Retrieve the interface addresses
if ( (nread+= sock_recv(sockctrl, (char *) &ifaddr,
sizeof(struct rpcap_findalldevs_ifaddr), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) ) == -1)
goto error;
// WARNING libpcap bug: the address listing is available only for AF_INET
if ( ntohs(ifaddr.addr.ss_family) == AF_INET)
{
struct pcap_addr *addr;
if (naddr == 0)
{
dev->addresses= (struct pcap_addr *) malloc ( sizeof(struct pcap_addr) );
addr= dev->addresses;
}
else
{
addr->next= (struct pcap_addr *) malloc ( sizeof(struct pcap_addr) );
addr= addr->next;
}
naddr++;
if (addr == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
goto error;
}
addr->next= NULL;
if (rpcap_deseraddr( (struct sockaddr_storage *) &ifaddr.addr,
(struct sockaddr_storage **) &addr->addr, errbuf) == -1)
goto error;
if (rpcap_deseraddr( (struct sockaddr_storage *) &ifaddr.netmask,
(struct sockaddr_storage **) &addr->netmask, errbuf) == -1)
goto error;
if (rpcap_deseraddr( (struct sockaddr_storage *) &ifaddr.broadaddr,
(struct sockaddr_storage **) &addr->broadaddr, errbuf) == -1)
goto error;
if (rpcap_deseraddr( (struct sockaddr_storage *) &ifaddr.dstaddr,
(struct sockaddr_storage **) &addr->dstaddr, errbuf) == -1)
goto error;
if ( (addr->addr == NULL) && (addr->netmask == NULL) &&
(addr->broadaddr == NULL) && (addr->dstaddr == NULL) )
{
free(addr);
addr= NULL;
if (naddr == 1)
naddr= 0; // the first item of the list had NULL addresses
}
}
}
}
// 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, errbuf, PCAP_ERRBUF_SIZE) == 1)
return -1;
}
// Control connection has to be closed only in case the remote machine is in passive mode
if (!active)
{
// DO not send RPCAP_CLOSE, since we did not open a pcap_t; no need to free resources
if ( sock_close(sockctrl, errbuf, PCAP_ERRBUF_SIZE) )
return -1;
}
// To avoid inconsistencies in the number of sock_init()
sock_cleanup();
return 0;
error:
// In case there has been an error, I don't want to overwrite it with a new one
// if the following call fails. I want to return always the original error.
//
// Take care: this connection can already be closed when we try to close it.
// This happens because a previous error in the rpcapd, which requested to
// closed the connection. In that case, we already recognized that into the
// rpspck_isheaderok() and we already acknowledged the closing.
// In that sense, this call is useless here (however it is needed in case
// the client generates the error).
// 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)
return -1;
}
// Control connection has to be closed only in case the remote machine is in passive mode
if (!active)
sock_close(sockctrl, NULL, 0);
// To avoid inconsistencies in the number of sock_init()
sock_cleanup();
return -1;
}
/*! \ingroup wpcapfunc
\brief Accepts a set of strings (host name, port, ...), and it returns the complete
source string according to the new format (e.g. 'rpcap://1.2.3.4/eth0').
This function is provided in order to help the user creating the source string
according to the new format.
An unique source string is used in order to make easy for old applications to use the
remote facilities. Think about tcpdump, for example, which has only one way to specify
the interface on which the capture has to be started.
However, GUI-based programs can find more useful to specify hostname, port and
interface name separately. In that case, they can use this function to create the
source string before passing it to the pcap_open() function.
\param source: a user-allocated buffer that will contain the complete source string
wen the function returns.<br>
The source will start with an identifier according to the new \link remote_source_string
Source Specification Syntax \endlink.<br>
This function assumes that the allocated buffer is at least PCAP_BUF_SIZE bytes.
\param type: its value tells the type of the source we want to create. It can assume
the values defined in the \link remote_source_ID Source identification
Codes \endlink.<br>
\param host: an user-allocated buffer that keeps the host (e.g. "foo.bar.com") we
want to connect to.
It can be NULL in case we want to open an interface on a local host.
\param port: an user-allocated buffer that keeps the network port (e.g. "2002") we
want to use for the RPCAP protocol.
It can be NULL in case we want to open an interface on a local host.
\param name: an user-allocated buffer that keeps the interface name we want to use
(e.g. "eth0").
It can be NULL in case the return string (i.e. 'source') has to be used with the
pcap_findalldevs_ex(), which does not require the interface name.
\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 string containing
the complete source is returned in the 'source' variable.
\warning If the source is longer than PCAP_BUF_SIZE, the excess characters are truncated.
*/
int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf)
{
switch (type)
{
case PCAP_SRC_FILE:
{
strncpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
if ((name) && (*name) )
{
strncat(source, name, PCAP_BUF_SIZE);
return 0;
}
else
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name cannot be NULL.");
return -1;
}
}
case PCAP_SRC_IFREMOTE:
{
strncpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
if ((host) && (*host) )
{
if ( (strcspn(host, "aAbBcCdDeEfFgGhHjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ")) == strlen(host) )
{
// the host name does not contains alphabetic chars. So, it is a numeric address
// In this case we have to include it between square brackets
strncat(source, "[", PCAP_BUF_SIZE);
strncat(source, host, PCAP_BUF_SIZE);
strncat(source, "]", PCAP_BUF_SIZE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -