static int pcap_setfilter_rpcap(pcap_t *fp, struct bpf_program *prog);
static int pcap_setsampling_remote(pcap_t *fp);
static int pcap_startcapture_remote(pcap_t *fp);
-static int rpcap_sendauth(SOCKET sock, SSL *, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf);
static int rpcap_recv_msg_header(SOCKET sock, SSL *, struct rpcap_header *header, char *errbuf);
static int rpcap_check_msg_ver(SOCKET sock, SSL *, uint8 expected_ver, struct rpcap_header *header, char *errbuf);
static int rpcap_check_msg_type(SOCKET sock, SSL *, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf);
/*
* This function performs authentication and protocol version
- * negotiation. It first tries to authenticate with the maximum
- * version we support and, if that fails with an "I don't support
- * that version" error from the server, and the version number in
- * the reply from the server is one we support, tries again with
- * that version.
+ * negotiation. It is required in order to open the connection
+ * with the other end party.
+ *
+ * It sends authentication parameters on the control socket and
+ * reads the reply. If the reply is a success indication, it
+ * checks whether the reply includes minimum and maximum supported
+ * versions from the server; if not, it assumes both are 0, as
+ * that means it's an older server that doesn't return supported
+ * version numbers in authentication replies, so it only supports
+ * version 0. It then tries to determine the maximum version
+ * supported both by us and by the server. If it can find such a
+ * version, it sets us up to use that version; otherwise, it fails,
+ * indicating that there is no version supported by us and by the
+ * server.
*
* \param sock: the socket we are currently using.
*
- * \param ver: pointer to variable holding protocol version number to send
- * and to set to the protocol version number in the reply.
+ * \param ver: pointer to variable to which to set the protocol version
+ * number we selected.
*
* \param auth: authentication parameters that have to be sent.
*
* an error message string is returned in the 'errbuf' variable.
*/
static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf)
-{
- int status;
-
- /*
- * Send authentication to the remote machine.
- *
- * First try with the maximum version number we support.
- */
- *ver = RPCAP_MAX_VERSION;
- status = rpcap_sendauth(sockctrl, ssl, ver, auth, errbuf);
- if (status == 0)
- {
- //
- // Success.
- //
- return 0;
- }
- if (status == -1)
- {
- /* Unrecoverable error. */
- return -1;
- }
-
- /*
- * The server doesn't support the version we used in the initial
- * message, and it sent us back a reply either with the maximum
- * version they do support, or with the version we sent, and we
- * support that version. *ver has been set to that version; try
- * authenticating again with that version.
- */
- status = rpcap_sendauth(sockctrl, ssl, ver, auth, errbuf);
- if (status == 0)
- {
- //
- // Success.
- //
- return 0;
- }
- if (status == -1)
- {
- /* Unrecoverable error. */
- return -1;
- }
- if (status == -2)
- {
- /*
- * The server doesn't support that version, which
- * means there is no version we both support, so
- * this is a fatal error.
- */
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The server doesn't support any protocol version that we support");
- return -1;
- }
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "rpcap_sendauth() returned %d", status);
- return -1;
-}
-
-/*
- * This function sends the authentication message.
- *
- * It sends the authentication parameters on the control socket.
- * It is required in order to open the connection with the other end party.
- *
- * \param sock: the socket we are currently using.
- *
- * \param ver: pointer to variable holding protocol version number to send
- * and to set to the protocol version number in the reply.
- *
- * \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 a network problem or the fact that the authorization
- * failed.
- *
- * \return '0' if everything is fine, '-2' if the server didn't reply with
- * the protocol version we requested but replied with a version we do
- * support, or '-1' for other errors. For errors, an error message string
- * is returned in the 'errbuf' variable.
- */
-static int rpcap_sendauth(SOCKET sock, SSL *ssl, uint8 *ver, 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 */
- uint16 errcode;
struct rpcap_auth *rpauth;
uint16 auth_type;
struct rpcap_header header;
size_t str_length;
+ uint32 plen;
+ struct rpcap_authreply authreply; /* authentication reply message */
+ uint8 ourvers;
if (auth)
{
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, *ver,
+ rpcap_createhdr((struct rpcap_header *) sendbuf, 0,
RPCAP_MSG_AUTH_REQ, 0, length);
rpauth = (struct rpcap_auth *) &sendbuf[sendbufidx];
rpauth->slen2 = htons(rpauth->slen2);
}
- if (sock_send(sock, ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0)
+ if (sock_send(sockctrl, ssl, sendbuf, sendbufidx, errbuf,
+ PCAP_ERRBUF_SIZE) < 0)
return -1;
- /* Receive the reply */
- if (rpcap_recv_msg_header(sock, ssl, &header, errbuf) == -1)
+ /* Receive and process the reply message header */
+ if (rpcap_process_msg_header(sockctrl, ssl, 0, RPCAP_MSG_AUTH_REQ,
+ &header, errbuf) == -1)
return -1;
- if (rpcap_check_msg_type(sock, ssl, RPCAP_MSG_AUTH_REQ, &header,
- &errcode, errbuf) == -1)
+ /*
+ * OK, it's an authentication reply, so we're logged in.
+ *
+ * Did it send any additional information?
+ */
+ plen = header.plen;
+ if (plen != 0)
{
- /* Error message - or something else, which is a protocol error. */
- if (header.type == RPCAP_MSG_ERROR &&
- errcode == PCAP_ERR_WRONGVER)
+ /* Yes - is it big enough to be version information? */
+ if (plen < sizeof(struct rpcap_authreply))
{
- /*
- * The server didn't support the version we sent,
- * and replied with the maximum version it supports
- * if our version was too big or with the version
- * we sent if out version was too small.
- *
- * Do we also support it?
- */
- if (!RPCAP_VERSION_IS_SUPPORTED(header.ver))
- {
- /*
- * No, so there's no version we both support.
- * This is an unrecoverable error.
- */
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The server doesn't support any protocol version that we support");
- return -1;
- }
+ /* No - discard it and fail. */
+ (void)rpcap_discard(sockctrl, ssl, plen, NULL);
+ return -1;
+ }
- /*
- * OK, use that version, and tell our caller to
- * try again.
- */
- *ver = header.ver;
- return -2;
+ /* Read the reply body */
+ if (rpcap_recv(sockctrl, ssl, (char *)&authreply,
+ sizeof(struct rpcap_authreply), &plen, errbuf) == -1)
+ {
+ (void)rpcap_discard(sockctrl, ssl, plen, NULL);
+ return -1;
}
+ /* Discard the rest of the message, if there is any. */
+ if (rpcap_discard(sockctrl, ssl, plen, errbuf) == -1)
+ return -1;
+
/*
- * Other error - unrecoverable.
+ * Check the minimum and maximum versions for sanity;
+ * the minimum must be <= the maximum.
*/
- return -1;
+ if (authreply.minvers > authreply.maxvers)
+ {
+ /*
+ * Bogus - give up on this server.
+ */
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The server's minimum supported protocol version is greater than its maximum supported protocol version");
+ return -1;
+ }
+ }
+ else
+ {
+ /* No - it supports only version 0. */
+ authreply.minvers = 0;
+ authreply.maxvers = 0;
}
/*
- * OK, it's an authentication reply, so they're OK with the
- * protocol version we sent.
- *
- * Discard the rest of it.
+ * OK, let's start with the maximum version the server supports.
*/
- if (rpcap_discard(sock, ssl, header.plen, errbuf) == -1)
- return -1;
+ ourvers = authreply.maxvers;
+
+ /*
+ * If that's less than the minimum version we support, we
+ * can't communicate.
+ */
+ if (ourvers < RPCAP_MIN_VERSION)
+ goto novers;
+ /*
+ * If that's greater than the maximum version we support,
+ * choose the maximum version we support.
+ */
+ if (ourvers > RPCAP_MAX_VERSION)
+ {
+ ourvers = RPCAP_MAX_VERSION;
+
+ /*
+ * If that's less than the minimum version they
+ * support, we can't communicate.
+ */
+ if (ourvers < authreply.minvers)
+ goto novers;
+ }
+
+ *ver = ourvers;
return 0;
+
+novers:
+ /*
+ * There is no version we both support; that is a fatal error.
+ */
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "The server doesn't support any protocol version that we support");
+ return -1;
}
/* We don't currently support non-blocking mode. */
*
* Version negotiation is done as part of the authentication process:
*
- * The client sends an authentication request, with the version number
- * in the request being the maximum version it supports.
- *
- * If the server supports that version, it attempts to authenticate the
- * client, and replies as appropriate, with the version number in the
- * reply being that version.
- *
- * If the server doesn't support that version because it's too large,
- * it replies with a RPCAP_MSG_ERROR message, with the maximum version
- * they support as the version number in the reply, and with the error
- * code being PCAP_ERR_WRONGVER.
- *
- * If the server doesn't support that version because it's too small,
- * it replies with a RPCAP_MSG_ERROR message, with that version as
- * the version number in the reply, and with the error code being
- * PCAP_ERR_WRONGVER.
- *
- * If the client supports that version, it retries the authentication
- * with that version and, if that fails for any reason, including
- * PCAP_ERR_WRONGVER, fails. Otherwise, it fails, telling its caller
- * that there's no version that both support.
- *
- * This requires that the set of versions supported by a client or
- * server be a range of integers, with no gaps. Thus:
- *
- * the client's version set is [Cmin, Cmax], with Cmin <= Cmax;
- *
- * the server's version set is [Smin, Smax], with Smin <= Smax;
- *
- * the client sends Cmax as the version number in the initial
- * authentication request;
- *
- * if the server doesn't support the version sent by the client,
- * either Smax < Cmax or Smin > Cmax (because the client sent Cmax
- * to the server, and the server doesn't support it);
- *
- * if Smax < Cmax:
- *
- * the server sends Smax as the version number in the RPCAP_MSG_ERROR/
- * PCAP_ERR_WRONGVER message - the client will accept this because
- * Cmax != 0, as these numbers are unsigned, and this means that
- * this isn't an old client that rejects all messages with a non-zero
- * version number, it's a new client that accepts RPCAP_MSG_ERROR
- * messages no matter what the version is;
- *
- * if Smax >= Cmin, both the client and the server can use it, and
- * the client retries with Smax;
- *
- * if Smax < Cmin, there is no version the client and server can
- * both support.
- *
- * if Smin > Cmax:
- *
- * the server sends Cmax as the version number in the RPCAP_MSG_ERROR/
- * PCAP_ERR_WRONGVER message - the client will accept this because
- * Cmax is a valid client version number.
- *
- * the client will retry with Cmax, get the same version failure,
- * and report that there is no version the client and server can
- * both support (as the version sets are disjoint).
- *
- * Old negotiation-unaware clients just send version 0 and, if they
- * get back PCAP_ERR_WRONGVER, treat it as a fatal error. This
- * means they'll fail to talk to any server that can't handle
- * version 0, which is the appropriate thing to do, as they can
- * only use version 0.
- *
- * Old negotiation-unaware servers fail if they get a version other
- * than 0, sending back PCAP_ERR_WRONGVER with version 0, which is
- * the only version, and thus both the minimum and maximum version,
- * they support. The client will either fail if it doesn't support
- * version 0, or will retry with version 0 and succeed, so it will
- * fail with servers that can't handle version 0 or will negotiate
- * version 0 with servers that can handle version 0.
+ * The client sends an authentication request, with a version number
+ * of 0. All servers must accept authentication requests with a version
+ * number of 0, even if they don't support version 0 for any other
+ * requests.
+ *
+ * The server attempts to authenticate the client. If that succeeds,
+ * older servers - which only support version 0 - will send an
+ * authentication reply with no payload. Newer servers - which might
+ * support other versions - will send an authentication reply with
+ * a payload giving the minimum and maximum versions it supports.
+ *
+ * The client attempts to find the largest version number that is
+ * in both its range of supported versions and the server's supported
+ * versions. If it fails, it gives up; otherwise, it uses that version.
*/
#define RPCAP_MIN_VERSION 0
#define RPCAP_MAX_VERSION 0
-/*
- * So that the server can distinguish between a non-TLS rpcapd
- * message, the first byte of which is the version number, and
- * a TLS client hello, the first byte of which is 22, we don't
- * allow 22 as an rpcap version number.
- */
-#define RPCAP_UNUSED_VERSION 22
-
-/*
- * Make sure nobody makes the mistake of making the "must not use" version
- * the minimum or maximum version; we *must* allow at least one version
- * other than that version.
- */
-#if RPCAP_MIN_VERSION == RPCAP_UNUSED_VERSION
- #error Minimum protocol version is a version that must not be used
-#elif RPCAP_MAX_VERSION == RPCAP_UNUSED_VERSION
- #error Maximum protocol version is a version that must not be used
-#endif
-
/*
* Version numbers are unsigned, so if RPCAP_MIN_VERSION is 0, they
* are >= the minimum version, by definition; don't check against
* RPCAP_MIN_VERSION, as you may get compiler warnings that the
* comparison will always succeed.
- *
- * We *never* allow version RPCAP_UNUSED_VERSION, even if it's
- * otherwise in the allowed range.
*/
#if RPCAP_MIN_VERSION == 0
#define RPCAP_VERSION_IS_SUPPORTED(v) \
- ((v) <= RPCAP_MAX_VERSION && (v) != RPCAP_UNUSED_VERSION)
+ ((v) <= RPCAP_MAX_VERSION)
#else
#define RPCAP_VERSION_IS_SUPPORTED(v) \
- ((v) >= RPCAP_MIN_VERSION && (v) <= RPCAP_MAX_VERSION && \
- (v) != RPCAP_UNUSED_VERSION)
+ ((v) >= RPCAP_MIN_VERSION && (v) <= RPCAP_MAX_VERSION)
#endif
/*
uint32 plen; /* Length of the payload of this RPCAP message */
};
+/*
+ * Format of data that may appear at the end of an authentication reply,
+ * giving the minimum and maximum versions of the protocol that the
+ * server supports.
+ *
+ * Older servers don't provide this; they support only version 0.
+ */
+struct rpcap_authreply
+{
+ uint8 minvers; /* Minimum version supported */
+ uint8 maxvers; /* Maximum version supported */
+};
+
/* Format of the message for the interface description (findalldevs command) */
struct rpcap_findalldevs_if
{
{
SOCKET sockctrl; //!< SOCKET ID of the control connection
SSL *ssl; //!< Optional SSL handler for the controlling sockets
- uint8 protocol_version; //!< negotiated protocol version
int isactive; //!< Not null if the daemon has to run in active mode
int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise
};
static int daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen);
static int daemon_AuthUserPwd(char *username, char *password, char *errbuf);
-static int daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen);
+static int daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars,
+ uint32 plen);
-static int daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_t sourcelen);
-static int daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, char *source, struct session **sessionp, struct rpcap_sampling *samp_param, int uses_ssl);
-static int daemon_msg_endcap_req(struct daemon_slpars *pars, struct session *session);
+static int daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars,
+ uint32 plen, char *source, size_t sourcelen);
+static int daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars,
+ uint32 plen, char *source, struct session **sessionp,
+ struct rpcap_sampling *samp_param, int uses_ssl);
+static int daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars,
+ struct session *session);
-static int daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session, uint32 plen);
+static int daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars,
+ struct session *session, uint32 plen);
static int daemon_unpackapplyfilter(SOCKET sockctrl, SSL *, struct session *session, uint32 *plenp, char *errbuf);
-static int daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32 plen, struct pcap_stat *stats, unsigned int svrcapt);
+static int daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars,
+ struct session *session, uint32 plen, struct pcap_stat *stats,
+ unsigned int svrcapt);
-static int daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap_sampling *samp_param);
+static int daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars,
+ uint32 plen, struct rpcap_sampling *samp_param);
static void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *sockaddrout);
#ifdef _WIN32
// a TLS handshake message or a non-TLS rpcapd message.
//
// The first byte of an rpcapd request is the version number;
- // the first byte of a TLS handshake message is 22. We
- // permanently reserve an rpcapd version number of 22, so that
- // we can distinguish between rpcapd messages and TLS handshake
- // messages; if we ever get to rpcapd version 21, and want to
- // introduce a new version after that, we'll jump to version 23.
+ // the first byte of a TLS handshake message is 22. The
+ // first request to an rpcapd server must be an authentication
+ // request or a close request, and must have a version number
+ // of 0, so it will be possible to distinguish between an
+ // initial plaintext request to a server and an initial TLS
+ // handshake message.
//
nrecv = sock_recv(sockctrl, NULL, (char *)&first_octet, 1,
SOCK_EOF_ISNT_ERROR|SOCK_MSG_PEEK, errbuf, PCAP_ERRBUF_SIZE);
// Set parameters structure
pars.sockctrl = sockctrl;
pars.ssl = ssl;
- pars.protocol_version = 0; // not yet known
pars.isactive = isactive; // active mode
pars.nullAuthAllowed = nullAuthAllowed;
plen = header.plen;
//
- // Did the client specify a version we can handle?
+ // While we're in the authentication pharse, all requests
+ // must use version 0.
//
- if (!RPCAP_VERSION_IS_SUPPORTED(header.ver))
+ if (header.ver != 0)
{
//
- // Tell them it's not a valid protocol version.
- //
- uint8 reply_version;
-
- //
- // If RPCAP_MIN_VERSION is 0, no version is too
- // old, as the oldest supported version is 0,
- // and there are no negative versions.
+ // Send it back to them with their version.
//
-#if RPCAP_MIN_VERSION != 0
- if (header.ver < RPCAP_MIN_VERSION)
- {
- //
- // Their maximum version is too old;
- // there *is* no version we can both
- // handle, and they might reject
- // an error with a version they don't
- // understand, so reply with the
- // version they sent. That may
- // make them retry with that version,
- // but they'll give up on that
- // failure.
- //
- reply_version = header.ver;
- }
- else
-#endif
- {
- //
- // Their maximum version is too new,
- // but they might be able to handle
- // *our* maximum version, so reply
- // with that version.
- //
- reply_version = RPCAP_MAX_VERSION;
- }
- if (rpcap_senderror(pars.sockctrl, pars.ssl, reply_version,
- PCAP_ERR_WRONGVER, "RPCAP version number mismatch",
+ if (rpcap_senderror(pars.sockctrl, pars.ssl, header.ver,
+ PCAP_ERR_WRONGVER,
+ "RPCAP version in requests in the authentication phase must be 0",
errbuf) == -1)
{
// That failed; log a message and give up.
goto end;
}
- // Discard the rest of the message.
- if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1)
- {
- // Network error.
- goto end;
- }
-
- // Let them try again.
- continue;
+ // Discard the rest of the message and drop the
+ // connection.
+ (void)rpcapd_discard(pars.sockctrl, pars.ssl, plen);
+ goto end;
}
- //
- // OK, we use the version the client specified.
- //
- pars.protocol_version = header.ver;
-
switch (header.type)
{
case RPCAP_MSG_AUTH_REQ:
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type);
}
if (rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version, PCAP_ERR_WRONGMSG,
+ header.ver, PCAP_ERR_WRONGMSG,
errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
}
if (rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version, PCAP_ERR_WRONGMSG,
+ header.ver, PCAP_ERR_WRONGMSG,
errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
//
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
if (rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version, PCAP_ERR_WRONGMSG,
+ header.ver, PCAP_ERR_WRONGMSG,
errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
{
sock_geterror("select failed: ", errmsgbuf, PCAP_ERRBUF_SIZE);
if (rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version, PCAP_ERR_NETW,
+ header.ver, PCAP_ERR_NETW,
errmsgbuf, errbuf) == -1)
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
goto end;
if (retval == 0)
{
if (rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version,
+ header.ver,
PCAP_ERR_INITTIMEOUT,
"The RPCAP initial timeout has expired",
errbuf) == -1)
plen = header.plen;
//
- // Did the client specify the version we negotiated?
+ // Did the client specify a protocol version that we
+ // support?
//
- // For now, there's only one version.
- //
- if (header.ver != pars.protocol_version)
+ if (!RPCAP_VERSION_IS_SUPPORTED(header.ver))
{
//
- // Tell them it's not the negotiated version.
+ // Tell them it's not a supported version.
// Send the error message with their version,
// so they don't reject it as having the wrong
// version.
//
if (rpcap_senderror(pars.sockctrl, pars.ssl,
header.ver, PCAP_ERR_WRONGVER,
- "RPCAP version in message isn't the negotiated version",
+ "RPCAP version in message isn't supported by the server",
errbuf) == -1)
{
// That failed; log a message and give up.
case RPCAP_MSG_FINDALLIF_REQ:
{
- if (daemon_msg_findallif_req(&pars, plen) == -1)
+ if (daemon_msg_findallif_req(header.ver, &pars, plen) == -1)
{
// Fatal error; a message has
// been logged, so just give up.
// us multiple open requests, the last
// one wins.
//
- retval = daemon_msg_open_req(&pars, plen, source, sizeof(source));
+ retval = daemon_msg_open_req(header.ver, &pars,
+ plen, source, sizeof(source));
if (retval == -1)
{
// Fatal error; a message has
// They never told us what device
// to capture on!
if (rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version,
+ header.ver,
PCAP_ERR_STARTCAPTURE,
"No capture device was specified",
errbuf) == -1)
break;
}
- if (daemon_msg_startcap_req(&pars, plen, source, &session, &samp_param, uses_ssl) == -1)
+ if (daemon_msg_startcap_req(header.ver, &pars,
+ plen, source, &session, &samp_param,
+ uses_ssl) == -1)
{
// Fatal error; a message has
// been logged, so just give up.
{
if (session)
{
- if (daemon_msg_updatefilter_req(&pars, session, plen) == -1)
+ if (daemon_msg_updatefilter_req(header.ver,
+ &pars, session, plen) == -1)
{
// Fatal error; a message has
// been logged, so just give up.
else
{
if (rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version,
+ header.ver,
PCAP_ERR_UPDATEFILTER,
"Device not opened. Cannot update filter",
errbuf) == -1)
case RPCAP_MSG_STATS_REQ:
{
- if (daemon_msg_stats_req(&pars, session, plen, &stats, svrcapt) == -1)
+ if (daemon_msg_stats_req(header.ver, &pars,
+ session, plen, &stats, svrcapt) == -1)
{
// Fatal error; a message has
// been logged, so just give up.
svrcapt = 0;
}
- if (daemon_msg_endcap_req(&pars, session) == -1)
+ if (daemon_msg_endcap_req(header.ver,
+ &pars, session) == -1)
{
free(session);
session = NULL;
else
{
rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version,
+ header.ver,
PCAP_ERR_ENDCAPTURE,
"Device not opened. Cannot close the capture",
errbuf);
case RPCAP_MSG_SETSAMPLING_REQ:
{
- if (daemon_msg_setsampling_req(&pars, plen, &samp_param) == -1)
+ if (daemon_msg_setsampling_req(header.ver,
+ &pars, plen, &samp_param) == -1)
{
// Fatal error; a message has
// been logged, so just give up.
//
rpcapd_log(LOGPRIO_INFO, "The client sent an RPCAP_MSG_AUTH_REQ message after authentication was completed");
if (rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version,
+ header.ver,
PCAP_ERR_WRONGMSG,
"RPCAP_MSG_AUTH_REQ request sent after authentication was completed",
errbuf) == -1)
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
}
if (rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version, PCAP_ERR_WRONGMSG,
+ header.ver, PCAP_ERR_WRONGMSG,
errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
rpcapd_log(LOGPRIO_INFO, "The client sent a message of type %u", header.type);
pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
if (rpcap_senderror(pars.sockctrl, pars.ssl,
- pars.protocol_version, PCAP_ERR_WRONGMSG,
+ header.ver, PCAP_ERR_WRONGMSG,
errbuf, errmsgbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
{
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
- struct rpcap_header header; // RPCAP message general header
int status;
struct rpcap_auth auth; // RPCAP authentication header
+ 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
+ struct rpcap_authreply *authreply; // authentication reply message
status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf);
if (status == -1)
free(username);
free(passwd);
if (rpcap_senderror(pars->sockctrl, pars->ssl,
- pars->protocol_version,
- PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1)
+ 0, PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
}
// The authentication succeeded; let the client know.
- rpcap_createhdr(&header, pars->protocol_version, RPCAP_MSG_AUTH_REPLY, 0, 0);
+ if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
+ RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
+ goto error;
- // Send the ok message back
- if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+ rpcap_createhdr((struct rpcap_header *) sendbuf, 0,
+ RPCAP_MSG_AUTH_REPLY, 0, sizeof(struct rpcap_authreply));
+
+ authreply = (struct rpcap_authreply *) &sendbuf[sendbufidx];
+
+ if (sock_bufferize(NULL, sizeof(struct rpcap_authreply), NULL, &sendbufidx,
+ RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
+ goto error;
+
+ //
+ // Indicate to our peer what versions we support.
+ //
+ memset(authreply, 0, sizeof(struct rpcap_authreply));
+ authreply->minvers = RPCAP_MIN_VERSION;
+ authreply->maxvers = RPCAP_MAX_VERSION;
+
+ // Send the reply.
+ if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
{
// That failed; log a messsage and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
return 0;
error:
- if (rpcap_senderror(pars->sockctrl, pars->ssl, pars->protocol_version,
- PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, 0, PCAP_ERR_AUTH,
+ errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
}
static int
-daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen)
+daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen)
{
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
if (alldevs == NULL)
{
- if (rpcap_senderror(pars->sockctrl, pars->ssl, pars->protocol_version,
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
PCAP_ERR_NOREMOTEIF,
"No interfaces found! Make sure libpcap/WinPcap is properly installed"
" and you have the right to access to the remote device.",
PCAP_ERRBUF_SIZE) == -1)
goto error;
- rpcap_createhdr((struct rpcap_header *) sendbuf, pars->protocol_version,
+ rpcap_createhdr((struct rpcap_header *) sendbuf, ver,
RPCAP_MSG_FINDALLIF_REPLY, nif, plen);
// send the interface list
if (alldevs)
pcap_freealldevs(alldevs);
- if (rpcap_senderror(pars->sockctrl, pars->ssl, pars->protocol_version,
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
PCAP_ERR_FINDALLIF, errmsgbuf, errbuf) == -1)
{
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
to discard excess data in the message, if present)
*/
static int
-daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_t sourcelen)
+daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
+ char *source, size_t sourcelen)
{
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
goto error;
- rpcap_createhdr((struct rpcap_header *) sendbuf, pars->protocol_version,
+ rpcap_createhdr((struct rpcap_header *) sendbuf, ver,
RPCAP_MSG_OPEN_REPLY, 0, sizeof(struct rpcap_openreply));
openreply = (struct rpcap_openreply *) &sendbuf[sendbufidx];
return 0;
error:
- if (rpcap_senderror(pars->sockctrl, pars->ssl, pars->protocol_version,
- PCAP_ERR_OPEN, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_OPEN,
+ errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
to discard excess data in the message, if present)
*/
static int
-daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, char *source, struct session **sessionp, struct rpcap_sampling *samp_param _U_, int uses_ssl)
+daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
+ char *source, struct session **sessionp,
+ struct rpcap_sampling *samp_param _U_, int uses_ssl)
{
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
// Needed to send an error on the ctrl connection
session->sockctrl = pars->sockctrl;
session->ctrl_ssl = pars->ssl;
- session->protocol_version = pars->protocol_version;
+ session->protocol_version = ver;
// Now I can set the filter
ret = daemon_unpackapplyfilter(pars->sockctrl, pars->ssl, session, &plen, errmsgbuf);
RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
goto error;
- rpcap_createhdr((struct rpcap_header *) sendbuf, pars->protocol_version,
+ rpcap_createhdr((struct rpcap_header *) sendbuf, ver,
RPCAP_MSG_STARTCAP_REPLY, 0, sizeof(struct rpcap_startcapreply));
startcapreply = (struct rpcap_startcapreply *) &sendbuf[sendbufidx];
free(session);
}
- if (rpcap_senderror(pars->sockctrl, pars->ssl, pars->protocol_version,
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, ver,
PCAP_ERR_STARTCAPTURE, errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
}
static int
-daemon_msg_endcap_req(struct daemon_slpars *pars, struct session *session)
+daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars,
+ struct session *session)
{
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
struct rpcap_header header;
session_close(session);
- rpcap_createhdr(&header, pars->protocol_version,
- RPCAP_MSG_ENDCAP_REPLY, 0, 0);
+ rpcap_createhdr(&header, ver, RPCAP_MSG_ENDCAP_REPLY, 0, 0);
if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
{
}
static int
-daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session, uint32 plen)
+daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars,
+ struct session *session, uint32 plen)
{
char errbuf[PCAP_ERRBUF_SIZE];
char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
}
// A response is needed, otherwise the other host does not know that everything went well
- rpcap_createhdr(&header, pars->protocol_version,
- RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0);
+ rpcap_createhdr(&header, ver, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0);
if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE))
{
{
return -1;
}
- rpcap_senderror(pars->sockctrl, pars->ssl, pars->protocol_version,
- PCAP_ERR_UPDATEFILTER, errmsgbuf, NULL);
+ rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_UPDATEFILTER,
+ errmsgbuf, NULL);
return 0;
}
\brief Received the sampling parameters from remote host and it stores in the pcap_t structure.
*/
static int
-daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap_sampling *samp_param)
+daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars, uint32 plen,
+ struct rpcap_sampling *samp_param)
{
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
char errmsgbuf[PCAP_ERRBUF_SIZE];
samp_param->value = ntohl(rpcap_samp.value);
// A response is needed, otherwise the other host does not know that everything went well
- rpcap_createhdr(&header, pars->protocol_version,
- RPCAP_MSG_SETSAMPLING_REPLY, 0, 0);
+ rpcap_createhdr(&header, ver, RPCAP_MSG_SETSAMPLING_REPLY, 0, 0);
if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
{
return 0;
error:
- if (rpcap_senderror(pars->sockctrl, pars->ssl, pars->protocol_version,
- PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1)
+ if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_AUTH,
+ errmsgbuf, errbuf) == -1)
{
// That failed; log a message and give up.
rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
}
static int
-daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32 plen, struct pcap_stat *stats, unsigned int svrcapt)
+daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars,
+ struct session *session, uint32 plen, struct pcap_stat *stats,
+ unsigned int svrcapt)
{
char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors
char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client
&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1)
goto error;
- rpcap_createhdr((struct rpcap_header *) sendbuf, pars->protocol_version,
+ rpcap_createhdr((struct rpcap_header *) sendbuf, ver,
RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats));
netstats = (struct rpcap_stats *) &sendbuf[sendbufidx];
return 0;
error:
- rpcap_senderror(pars->sockctrl, pars->ssl, pars->protocol_version,
- PCAP_ERR_GETSTATS, errmsgbuf, NULL);
+ rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_GETSTATS,
+ errmsgbuf, NULL);
return 0;
}