📄 pcap-new.c
字号:
\ingroup wpcapfunc
\brief It blocks until a network connection is accepted (active mode only).
This function has been defined to allow the client dealing with the 'active mode'.
In other words, in the 'active mode' the server opens the connection toward the
client, so that the client has to open a socket in order to wait for connections.
When a new connection is accepted, the RPCAP protocol starts as usual; the only
difference is that the connection is initiated by the server.
This function accepts only ONE connection, then it closes the waiting socket. This means
that if some error occurs, the application has to call it again in order to accept another
connection.
This function returns when a new connection (coming from a valid host 'connectinghost')
is accepted; it returns error otherwise.
\param address: a string that keeps the network address we have to bind to;
usually it is NULL (it means 'bind on all local addresses').
\param port: a string that keeps the network port on which we have to bind to; usually
it is NULL (it means 'bind on the predefined port', i.e. RPCAP_DEFAULT_NETPORT_ACTIVE).
\param hostlist: a string that keeps the host name of the host from whom we are
expecting a connection; it can be NULL (it means 'accept connection from everyone').
Host names are separated by a whatever character in the RPCAP_HOSTLIST_SEP list.
\param connectinghost: a user-allocated buffer that will contain the name of the host
is trying to connect to us.
This variable must be at least RPCAP_HOSTLIST_SIZE bytes..
\param auth: a pointer to a pcap_rmtauth structure. This pointer keeps the information
required to authenticate the RPCAP connection to the remote host.
\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 The SOCKET identifier of the new control connection if everything is fine,
a negative number if some errors occurred. The error message is returned into the errbuf variable.
In case it returns '-1', this means 'everything is fine', but the host cannot be admitted.
In case it returns '-2', in means 'unrecoverable error' (for example it is not able to bind the
socket, or something like that).
In case it returns '-3', it means 'authentication failed'. The authentication check is performed
only if the connecting host is among the ones that are allowed to connect to this host.
The host that is connecting to us is returned into the hostlist variable, which ust be allocated
by the user. This variable contains the host name both in case the host is allowed,
and in case the connection is refused.
\warning Although this function returns the socket established by the new control connection,
this value should not be used. This value will be stored into some libpcap internal
variables and it will be managed automatically by the library. In other words, all the
following calls to findalldevs() and pcap_open() will check if the host is among one that
already has a control connection in place; if so, that one will be used.
\warning This function has several problems if used inside a thread, which is stopped
when this call is blocked into the accept(). In this case, the socket on which we accept
connections is not freed (thread termination is a very dirty job), so that we are no
longer able to accept other connections until the program (i.e. the process) stops.
In order to solve the problem, call the pcap_remoteact_cleanup().
*/
SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf)
{
// socket-related variables
struct addrinfo hints; // temporary struct to keep settings needed to open the new socket
struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
struct sockaddr_storage from; // generic sockaddr_storage variable
socklen_t fromlen; // keeps the length of the sockaddr_storage variable
SOCKET sockctrl; // keeps the main socket identifier
struct activehosts *temp, *prev; // temp var needed to scan he host list chain
*connectinghost= 0; // just in case
// Prepare to open a new server socket
memset(&hints, 0, sizeof(struct addrinfo));
// WARNING Currently it supports only ONE socket family among ipv4 and IPv6
hints.ai_family = AF_INET; // PF_UNSPEC to have both IPv4 and IPv6 server
hints.ai_flags = AI_PASSIVE; // Ready to a bind() socket
hints.ai_socktype = SOCK_STREAM;
// 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;
// Do the work
if ((port == NULL) || (port[0] == 0) )
{
if (sock_initaddress(address, RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
SOCK_ASSERT(errbuf, 1);
return -2;
}
}
else
{
if (sock_initaddress(address, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
SOCK_ASSERT(errbuf, 1);
return -2;
}
}
if ( (sockmain= sock_open(addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == -1)
{
SOCK_ASSERT(errbuf, 1);
return -2;
}
// Connection creation
fromlen = sizeof(struct sockaddr_storage);
sockctrl= accept(sockmain, (struct sockaddr *) &from, &fromlen);
// We're not using sock_close, since we do not want to send a shutdown
// (which is not allowed on a non-connected socket)
closesocket(sockmain);
sockmain= 0;
if (sockctrl == -1)
{
sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE);
return -2;
}
// Get the numeric for of the name of the connecting host
if (getnameinfo( (struct sockaddr *) &from, fromlen, connectinghost, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST) )
{
sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL);
sock_close(sockctrl, NULL, 0);
return -1;
}
// checks if the connecting host is among the ones allowed
if (sock_check_hostlist((char *) hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0)
{
rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL);
sock_close(sockctrl, NULL, 0);
return -1;
}
// Send authentication to the remote machine
if ( rpcap_sendauth(sockctrl, auth, errbuf) == -1)
{
rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL);
sock_close(sockctrl, NULL, 0);
return -3;
}
// Checks that this host does not already have a cntrl connection in place
// Initialize pointers
temp= activeHosts;
prev= NULL;
while (temp)
{
// This host already has an active connection in place, so I don't have to update the host list
if (sock_cmpaddr(&temp->host, &from) == 0)
return sockctrl;
prev= temp;
temp= temp->next;
}
// The host does not exist in the list; so I have to update the list
if (prev)
{
prev->next= (struct activehosts *) malloc (sizeof (struct activehosts) );
temp= prev->next;
}
else
{
activeHosts= (struct activehosts *) malloc (sizeof (struct activehosts) );
temp= activeHosts;
}
if (temp == NULL)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL);
sock_close(sockctrl, NULL, 0);
return -1;
}
memcpy(&temp->host, &from, fromlen);
temp->sockctrl= sockctrl;
temp->next= NULL;
return sockctrl;
}
/*!
\ingroup wpcapfunc
\brief It drops an active connection (active mode only).
This function has been defined to allow the client dealing with the 'active mode'.
This function closes an active connection that is still in place and it purges
the host name from the 'activeHost' list.
From this point on, the client will not have any connection with that host in place.
\param host: a string that keeps the host name of the host for which we want to
close the active connection.
\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 error message is
returned into the errbuf variable.
*/
int pcap_remoteact_close(const char *host, char *errbuf)
{
struct activehosts *temp, *prev; // temp var needed to scan the host list chain
struct addrinfo hints, *addrinfo, *ai_next; // temp var needed to translate between hostname to its address
int retval;
temp= activeHosts;
prev= NULL;
// retrieve the network address corresponding to 'host'
addrinfo = NULL;
memset(&hints, 0, sizeof (struct addrinfo) );
hints.ai_family = PF_UNSPEC;
hints.ai_socktype= SOCK_STREAM;
retval = getaddrinfo(host, "0", &hints, &addrinfo);
if (retval != 0)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval));
return -1;
}
while (temp)
{
ai_next= addrinfo;
while(ai_next)
{
if (sock_cmpaddr(&temp->host, (struct sockaddr_storage *) ai_next->ai_addr ) == 0)
{
struct rpcap_header header;
// Close this connection
rpcap_createhdr( &header, RPCAP_MSG_CLOSE, 0, 0);
// I don't check for errors, since I'm going to close everything
sock_send(temp->sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE);
if (sock_close(temp->sockctrl, errbuf, PCAP_ERRBUF_SIZE) )
{
// To avoid inconsistencies in the number of sock_init()
sock_cleanup();
return -1;
}
if (prev)
prev->next= temp->next;
else
activeHosts= temp->next;
freeaddrinfo(addrinfo);
free(temp);
// To avoid inconsistencies in the number of sock_init()
sock_cleanup();
return 0;
}
ai_next= ai_next->ai_next;
}
prev= temp;
temp= temp->next;
}
if (addrinfo)
freeaddrinfo(addrinfo);
// To avoid inconsistencies in the number of sock_init()
sock_cleanup();
snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host you want to close the active connection is not known");
return -1;
}
/*!
\ingroup wpcapfunc
\brief Cleans the socket that is currently used in waiting active connections.
This function does a very dirty job. The fact is that is the waiting socket is not
freed if the pcap_remoteaccept() is killed inside a new thread. This function is
able to clean the socket in order to allow the next calls to pcap_remoteact_accept() to work.
This function is useful *only* if you launch pcap_remoteact_accept() inside a new thread,
and you stops (not very gracefully) the thread (for example because the user changed idea,
and it does no longer want to wait for an active connection).
So, basically, the flow should be the following:
- launch a new thread
- call the pcap_remoteact_accept
- if this new thread is killed, call pcap_remoteact_cleanup().
This function has no effects in other cases.
\return None.
*/
void pcap_remoteact_cleanup()
{
// Very dirty, but it works
if (sockmain)
{
closesocket(sockmain);
// To avoid inconsistencies in the number of sock_init()
sock_cleanup();
}
}
/*!
\ingroup wpcapfunc
\brief Returns the hostname of the host that have an active connection with us (active mode only).
This function has been defined to allow the client dealing with the 'active mode'.
This function returns the list of hosts that are currently having an active connection
with us. This function is useful in order to delete an active connection that is still
in place.
\param hostlist: a user-allocated string that will keep the list of host that are
currently connected with us.
\param sep: the character that has to be sued as a separator between the hosts (',' for example).
\param size: size of the hostlist buffer.
\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 error message is
returned into the errbuf variable.
*/
int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf)
{
struct activehosts *temp; // temp var needed to scan the host list chain
int len;
char hoststr[RPCAP_HOSTLIST_SIZE + 1];
temp= activeHosts;
len= 0;
*hostlist= 0;
while (temp)
{
//int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen)
// Get the numeric form of the name of the connecting host
if (sock_getascii_addrport( (struct sockaddr_storage *) &temp->host,hoststr,
RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST, errbuf, PCAP_ERRBUF_SIZE) != -1)
// if (getnameinfo( (struct sockaddr *) &temp->host, sizeof (struct sockaddr_storage), hoststr,
// RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST) )
{
// sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
return -1;
}
len= len + strlen(hoststr) + 1 /* the separator */;
if (len >= size)
{
snprintf(errbuf, PCAP_ERRBUF_SIZE, "The string you provided is not able to keep "
"the hostnames for all the active connections");
return -1;
}
strcat(hostlist, hoststr);
hostlist[len - 1]= sep;
hostlist[len]= 0;
temp= temp->next;
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -