📄 pcap-remote.c
字号:
/*********************************************************
* *
* Miscellaneous functions *
* *
*********************************************************/
/*! \ingroup remote_pri_func
\brief It sends a RPCAP error to the other peer.
This function has to be called when the main program detects an error. This funcion
will send on the other peer the 'buffer' specified by the user.
This function *does not* request a RPCAP CLOSE connection. A CLOSE command must be sent
explicitely by the program, since we do not know it the error can be recovered in some
way or it is a non-recoverable one.
\param sock: the socket we are currently using.
\param error: an user-allocated (and '0' termined) buffer that contains the error
description thas has to be transmitted on the other peer. The error message cannot
be longer than PCAP_ERRBUF_SIZE.
\param errcode: a integer which tells the other party the type of error we had;
currently is is not too much used.
\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). It could be network problem.
\return '0' if everything is fine, '-1' if some errors occurred. The error message is returned
in the 'errbuf' variable.
*/
int rpcap_senderror(SOCKET sock, char *error, unsigned short errcode, char *errbuf)
{
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
uint16 length;
length= (uint16) strlen(error);
if (length > PCAP_ERRBUF_SIZE)
length= PCAP_ERRBUF_SIZE;
rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_ERROR, errcode, length);
if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) )
return -1;
if ( sock_bufferize(error, length, sendbuf, &sendbufidx,
RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) )
return -1;
if ( sock_send(sock, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) )
return -1;
return 0;
}
/*! \ingroup remote_pri_func
\brief Sends the authentication message.
It sends the authentication parameters on the control socket.
Ths function is required in order to open the connection with the other end party.
\param sock: the socket we are currently using.
\param auth: authentication parameters that have to be sent.
\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). It could be network problem
ot the fact that the authorization failed.
\return '0' if everything is fine, '-1' if some errors occurred. The error message is returned
in the 'errbuf' variable.
The error message could be also 'the authentication failed'.
*/
int rpcap_sendauth(SOCKET sock, struct pcap_rmtauth *auth, char *errbuf)
{
char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data that has to be sent is buffered
int sendbufidx= 0; // index which keeps the number of bytes currently buffered
uint16 length; // length of the payload of this message
struct rpcap_auth *rpauth;
uint16 auth_type;
struct rpcap_header header;
int retval; // temp variable which stores functions return value
if (auth)
{
auth_type= auth->type;
switch (auth->type)
{
case RPCAP_RMTAUTH_NULL:
length= sizeof (struct rpcap_auth);
break;
case RPCAP_RMTAUTH_PWD:
length= sizeof (struct rpcap_auth);
if (auth->username) length+= strlen(auth->username);
if (auth->password) length+= strlen(auth->password);
break;
default:
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized.");
return -1;
}
}
else
{
auth_type= RPCAP_RMTAUTH_NULL;
length= sizeof (struct rpcap_auth);
}
if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) )
return -1;
rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_AUTH_REQ, 0, length);
rpauth= (struct rpcap_auth *) &sendbuf[sendbufidx];
if ( sock_bufferize(NULL, sizeof(struct rpcap_auth), NULL,
&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) )
return -1;
memset(rpauth, 0, sizeof (struct rpcap_auth) );
rpauth->type= htons(auth_type);
if (auth_type == RPCAP_RMTAUTH_PWD)
{
if (auth->username)
rpauth->slen1= strlen(auth->username);
else
rpauth->slen1= 0;
if ( sock_bufferize(auth->username, rpauth->slen1, sendbuf,
&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) )
return -1;
if (auth->password)
rpauth->slen2= strlen(auth->password);
else
rpauth->slen2= 0;
if ( sock_bufferize(auth->password, rpauth->slen2, sendbuf,
&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) )
return -1;
rpauth->slen1= htons (rpauth->slen1);
rpauth->slen2= htons (rpauth->slen2);
}
if ( sock_send(sock, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) )
return -1;
if ( sock_recv(sock, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1)
return -1;
retval= rpcap_checkmsg(errbuf, sock, &header, RPCAP_MSG_AUTH_REPLY, RPCAP_MSG_ERROR, 0);
if (retval != RPCAP_MSG_AUTH_REPLY) // the message is not the one expected
{
switch (retval)
{
case -3: // Unrecoverable network error
case -2: // The other endpoint sent a message that is not allowed here
case -1: // The other endpoint has a version number that is not compatible with our
// Do nothing; just exit from here; the error code is already into the errbuf
return -1;
case RPCAP_MSG_ERROR:
{
return -1;
};
default:
{
SOCK_ASSERT("Internal error", 0);
return -1;
};
}
}
if (ntohl(header.plen) )
{
if (sock_discard(sock, ntohl(header.plen), errbuf, PCAP_ERRBUF_SIZE) )
return -1;
}
return 0;
}
/*! \ingroup remote_pri_func
\brief Creates a structure of type rpcap_header.
This function is provided just because the creation of an rpcap header is quite a common
task. It accepts all the values that appears into an rpcap_header, and it puts them in
place using the proper hton() calls.
\param header: a pointer to a user-allocated buffer which will contain the serialized
header, ready to be sent on the network.
\param type: a value (in the host by order) which will be placed into the header.type
field and that represents the type of the current message.
\param value: a value (in the host by order) which will be placed into the header.value
field and that has a message-dependent meaning.
\param length: a value (in the host by order) which will be placed into the header.length
field and that represents the payload length of the message.
\return Nothing. The serialized header is returned into the 'header' variable.
*/
void rpcap_createhdr(struct rpcap_header *header, uint8 type, uint16 value, uint32 length)
{
memset(header, 0, sizeof (struct rpcap_header) );
header->ver= RPCAP_VERSION;
header->type= type;
header->value= htons(value);
header->plen= htonl(length);
}
/*! \ingroup remote_pri_func
\brief Checks if the header of the received message is correct.
This function is a way to easily check if the message received, in a certain
state of the RPCAP protocol Finite State Machine, is valid. This function accepts,
as a parameter, the list of message types that are allowed in a certain situation,
and it returns the one which occurs.
\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). It could be either problem
occurred inside this function (e.g. a network problem in case it tries to send an
error on the other peer and the send() call fails), an error message which has been
sent to us from the other party, or a version error (the message receive has a version
number that is incompabile with our).
\param sock: the socket that has to be used to receive data. This function can
read data from socket in case the version contained into the message is not compatible
with our. In that case, all the message is purged from the socket, so that the following
recv() calls will return a new message.
\param header: a pointer to and 'rpcap_header' structure that keeps the data received from
the network (still in network byte order) and that has to be checked.
\param first: this function has a variable number of parameters. From this point on,
all the messages that are valid in this context must be passed as parameters.
The message type list must be terminated with a '0' value, the null message type,
which means 'no more types to check'. The RPCAP protocol does not define anything with
message type equal to zero, so there is no ambiguity in using this value as a list terminator.
\return The message type of the message that has been detected. In case of errors (e.g. the
header contains a type that is not listed among the allowed types), this function will
return the following codes:
- (-1) if the version is incompatible.
- (-2) if the code is not among the one listed into the parameters list
- (-3) if a network error (connection reset, ...)
- RPCAP_MSG_ERROR if the message is an error message (it follow that the RPCAP_MSG_ERROR
could not be present in the allowed message-types list, becuase this function checks
for errors anyway)
In case either the version is incompatible or nothing matches (i.e. it returns '-1' or '-2'),
it discards the message body (i.e. it reads the remaining part of the message from the
network and it discards it) so that the application is ready to receive a new message.
*/
int rpcap_checkmsg(char *errbuf, SOCKET sock, struct rpcap_header *header, uint8 first, ...)
{
va_list ap;
uint8 type;
int32 len;
va_start(ap, first);
// Check if the present version of the protocol can handle this message
if ( rpcap_checkver(sock, header, errbuf) )
{
SOCK_ASSERT(errbuf, 1);
va_end(ap);
return -1;
}
type= first;
while ( type != 0 )
{
// The message matches with one of the types listed
// There is no need of conversions since both values are uint8
// Check if the other side reported an error.
// If yes, it retrieves it and it returns it back to the caller
if (header->type == RPCAP_MSG_ERROR)
{
len= ntohl(header->plen);
if (len >= PCAP_ERRBUF_SIZE)
{
if (sock_recv(sock, errbuf, PCAP_ERRBUF_SIZE - 1, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) )
return -3;
sock_discard(sock, len - (PCAP_ERRBUF_SIZE - 1), fakeerrbuf, PCAP_ERRBUF_SIZE);
// Put '\0' at the end of the string
errbuf[PCAP_ERRBUF_SIZE - 1]= 0;
}
else
{
if (sock_recv(sock, errbuf, len, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1)
return -3;
// Put '\0' at the end of the string
errbuf[len]= 0;
}
va_end(ap);
return header->type;
}
if (header->type == type)
{
va_end(ap);
return header->type;
}
// get next argument
type= va_arg(ap, int);
}
// we already have an error, so please discard this one
sock_discard(sock, ntohl(header->plen), fakeerrbuf, PCAP_ERRBUF_SIZE);
snprintf(errbuf, PCAP_ERRBUF_SIZE, "The other endpoint sent a message that is not allowed here.");
SOCK_ASSERT(errbuf, 1);
va_end(ap);
return -2;
}
/*! \ingroup remote_pri_func
\brief Checks if the version contained into the message is compatible with
the one handled by this implementation.
Right now, this function does not have any sophisticated task: if the versions
are different, it returns -1 and it discards the message.
It is expected that in the future this message will become more complex.
\param sock: the socket that has to be used to receive data. This function can
read data from socket in case the version contained into the message is not compatible
with our. In that case, all the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -