diff options
Diffstat (limited to 'rpcapd/daemon.c')
-rw-r--r-- | rpcapd/daemon.c | 269 |
1 files changed, 166 insertions, 103 deletions
diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c index e30eeef1..12b555ec 100644 --- a/rpcapd/daemon.c +++ b/rpcapd/daemon.c @@ -64,6 +64,11 @@ #include "daemon.h" #include "log.h" +#ifdef HAVE_OPENSSL +#include <openssl/ssl.h> +#include "sslutils.h" +#endif + #define RPCAP_TIMEOUT_INIT 90 /* Initial timeout for RPCAP connections (default: 90 sec) */ #define RPCAP_TIMEOUT_RUNTIME 180 /* Run-time timeout for RPCAP connections (default: 3 min) */ #define RPCAP_SUSPEND_WRONGAUTH 1 /* If the authentication is wrong, stops 1 sec before accepting a new auth message */ @@ -73,6 +78,7 @@ struct daemon_slpars { SOCKET sockctrl_in; //!< SOCKET ID of the input side of the control connection SOCKET sockctrl_out; //!< SOCKET ID of the output side 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 @@ -84,6 +90,7 @@ struct daemon_slpars struct session { SOCKET sockctrl_out; SOCKET sockdata; + SSL *ctrl_ssl, *data_ssl; // optional SSL handlers for sockctrl_out and sockdata. uint8 protocol_version; pcap_t *fp; unsigned int TotCapt; @@ -107,18 +114,18 @@ struct thread_handle { }; // Locally defined functions -static int daemon_msg_err(SOCKET sockctrl_in, uint32 plen); +static int daemon_msg_err(SOCKET sockctrl_in, SSL *, uint32 plen); 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_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, struct thread_handle *threaddata, char *source, struct session **sessionp, struct rpcap_sampling *samp_param); +static int daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_handle *threaddata, 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, struct thread_handle *threaddata); static int daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session, uint32 plen); -static int daemon_unpackapplyfilter(SOCKET sockctrl_in, struct session *session, uint32 *plenp, char *errbuf); +static int daemon_unpackapplyfilter(SOCKET sockctrl_in, 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); @@ -131,12 +138,13 @@ static unsigned __stdcall daemon_thrdatamain(void *ptr); static void *daemon_thrdatamain(void *ptr); #endif -static int rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp); -static int rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf); -static int rpcapd_discard(SOCKET sock, uint32 len); +static int rpcapd_recv_msg_header(SOCKET sock, SSL *, struct rpcap_header *headerp); +static int rpcapd_recv(SOCKET sock, SSL *, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf); +static int rpcapd_discard(SOCKET sock, SSL *, uint32 len); +static void session_close(struct session *); int -daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nullAuthAllowed) +daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, SSL *ssl, int isactive, int nullAuthAllowed, int uses_ssl) { struct daemon_slpars pars; // service loop parameters char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed @@ -167,6 +175,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // Set parameters structure pars.sockctrl_in = sockctrl_in; pars.sockctrl_out = sockctrl_out; + pars.ssl = ssl; pars.protocol_version = 0; // not yet known pars.isactive = isactive; // active mode pars.nullAuthAllowed = nullAuthAllowed; @@ -217,7 +226,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu if (retval == -1) { sock_geterror("select failed: ", errmsgbuf, PCAP_ERRBUF_SIZE); - if (rpcap_senderror(pars.sockctrl_out, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); goto end; } @@ -226,7 +235,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // So, this was a fake connection. Drop it down if (retval == 0) { - if (rpcap_senderror(pars.sockctrl_out, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1) + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1) rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); goto end; } @@ -235,7 +244,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // // Read the message header from the client. // - nrecv = rpcapd_recv_msg_header(pars.sockctrl_in, &header); + nrecv = rpcapd_recv_msg_header(pars.sockctrl_in, pars.ssl, &header); if (nrecv == -1) { // Fatal error. @@ -291,7 +300,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // reply_version = RPCAP_MAX_VERSION; } - if (rpcap_senderror(pars.sockctrl_out, reply_version, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, reply_version, PCAP_ERR_WRONGVER, "RPCAP version number mismatch", errbuf) == -1) { @@ -301,7 +310,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu } // Discard the rest of the message. - if (rpcapd_discard(pars.sockctrl_in, plen) == -1) + if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1) { // Network error. goto end; @@ -345,7 +354,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // Discard the rest of the message, if // there is anything more. // - (void)rpcapd_discard(pars.sockctrl_in, plen); + (void)rpcapd_discard(pars.sockctrl_in, pars.ssl, plen); // We're done with this client. goto end; @@ -357,7 +366,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // an error message rather than a "let // me log in" message, indicating that // we're not allowed to connect to them? - (void)daemon_msg_err(pars.sockctrl_in, plen); + (void)daemon_msg_err(pars.sockctrl_in, pars.ssl, plen); goto end; case RPCAP_MSG_FINDALLIF_REQ: @@ -380,7 +389,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu { pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type); } - if (rpcap_senderror(pars.sockctrl_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1) { @@ -388,7 +397,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu goto end; } // Discard the rest of the message. - if (rpcapd_discard(pars.sockctrl_in, plen) == -1) + if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1) { // Network error. goto end; @@ -416,7 +425,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu { pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type); } - if (rpcap_senderror(pars.sockctrl_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1) { @@ -424,7 +433,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu goto end; } // Discard the rest of the message. - if (rpcapd_discard(pars.sockctrl_in, plen) == -1) + if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1) { // Fatal error. goto end; @@ -436,7 +445,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // Unknown message type. // pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type); - if (rpcap_senderror(pars.sockctrl_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1) { @@ -444,7 +453,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu goto end; } // Discard the rest of the message. - if (rpcapd_discard(pars.sockctrl_in, plen) == -1) + if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1) { // Fatal error. goto end; @@ -496,7 +505,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu if (retval == -1) { sock_geterror("select failed: ", errmsgbuf, PCAP_ERRBUF_SIZE); - if (rpcap_senderror(pars.sockctrl_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); @@ -507,7 +516,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // So, this was a fake connection. Drop it down if (retval == 0) { - if (rpcap_senderror(pars.sockctrl_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", @@ -520,7 +529,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // // Read the message header from the client. // - nrecv = rpcapd_recv_msg_header(pars.sockctrl_in, &header); + nrecv = rpcapd_recv_msg_header(pars.sockctrl_in, pars.ssl, &header); if (nrecv == -1) { // Fatal error. @@ -547,7 +556,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // so they don't reject it as having the wrong // version. // - if (rpcap_senderror(pars.sockctrl_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, header.ver, PCAP_ERR_WRONGVER, "RPCAP version in message isn't the negotiated version", errbuf) == -1) @@ -558,7 +567,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu } // Discard the rest of the message. - (void)rpcapd_discard(pars.sockctrl_in, plen); + (void)rpcapd_discard(pars.sockctrl_in, pars.ssl, plen); // Give up on them. goto end; } @@ -567,7 +576,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu { case RPCAP_MSG_ERROR: // The other endpoint reported an error { - (void)daemon_msg_err(pars.sockctrl_in, plen); + (void)daemon_msg_err(pars.sockctrl_in, pars.ssl, plen); // Do nothing; just exit; the error code is already into the errbuf // XXX - actually exit.... break; @@ -612,7 +621,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu { // They never told us what device // to capture on! - if (rpcap_senderror(pars.sockctrl_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_STARTCAPTURE, "No capture device was specified", @@ -623,14 +632,14 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); goto end; } - if (rpcapd_discard(pars.sockctrl_in, plen) == -1) + if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1) { goto end; } break; } - if (daemon_msg_startcap_req(&pars, plen, &threaddata, source, &session, &samp_param) == -1) + if (daemon_msg_startcap_req(&pars, plen, &threaddata, source, &session, &samp_param, uses_ssl) == -1) { // Fatal error; a message has // been logged, so just give up. @@ -652,7 +661,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu } else { - if (rpcap_senderror(pars.sockctrl_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_UPDATEFILTER, "Device not opened. Cannot update filter", @@ -719,7 +728,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu } else { - rpcap_senderror(pars.sockctrl_out, + rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_ENDCAPTURE, "Device not opened. Cannot close the capture", @@ -746,7 +755,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // get to reauthenticate. // rpcapd_log(LOGPRIO_INFO, "The client sent an RPCAP_MSG_AUTH_REQ message after authentication was completed"); - if (rpcap_senderror(pars.sockctrl_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_WRONGMSG, "RPCAP_MSG_AUTH_REQ request sent after authentication was completed", @@ -756,7 +765,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu goto end; } // Discard the rest of the message. - if (rpcapd_discard(pars.sockctrl_in, plen) == -1) + if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1) { // Fatal error. goto end; @@ -786,7 +795,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu rpcapd_log(LOGPRIO_INFO, "The client sent a server-to-client message of type %u", header.type); pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type); } - if (rpcap_senderror(pars.sockctrl_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_WRONGMSG, errmsgbuf, errbuf) == -1) { @@ -794,7 +803,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu goto end; } // Discard the rest of the message. - if (rpcapd_discard(pars.sockctrl_in, plen) == -1) + if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1) { // Fatal error. goto end; @@ -807,7 +816,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu // 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_out, + if (rpcap_senderror(pars.sockctrl_out, pars.ssl, pars.protocol_version, PCAP_ERR_WRONGMSG, errbuf, errmsgbuf) == -1) { @@ -815,7 +824,7 @@ daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nu goto end; } // Discard the rest of the message. - if (rpcapd_discard(pars.sockctrl_in, plen) == -1) + if (rpcapd_discard(pars.sockctrl_in, pars.ssl, plen) == -1) { // Fatal error. goto end; @@ -865,12 +874,8 @@ end: #endif threaddata.have_thread = 0; } - if (session->sockdata) - { - sock_close(session->sockdata, NULL, 0); - session->sockdata = 0; - } - pcap_close(session->fp); + + session_close(session); free(session); session = NULL; } @@ -886,7 +891,7 @@ end: * This handles the RPCAP_MSG_ERR message. */ static int -daemon_msg_err(SOCKET sockctrl_in, uint32 plen) +daemon_msg_err(SOCKET sockctrl_in, SSL *ssl, uint32 plen) { char errbuf[PCAP_ERRBUF_SIZE]; char remote_errbuf[PCAP_ERRBUF_SIZE]; @@ -897,7 +902,7 @@ daemon_msg_err(SOCKET sockctrl_in, uint32 plen) * Message is too long; just read as much of it as we * can into the buffer provided, and discard the rest. */ - if (sock_recv(sockctrl_in, remote_errbuf, PCAP_ERRBUF_SIZE - 1, + if (sock_recv(sockctrl_in, ssl, remote_errbuf, PCAP_ERRBUF_SIZE - 1, SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE) == -1) { @@ -905,7 +910,7 @@ daemon_msg_err(SOCKET sockctrl_in, uint32 plen) rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); return -1; } - if (rpcapd_discard(sockctrl_in, plen - (PCAP_ERRBUF_SIZE - 1)) == -1) + if (rpcapd_discard(sockctrl_in, ssl, plen - (PCAP_ERRBUF_SIZE - 1)) == -1) { // Network error. return -1; @@ -923,7 +928,7 @@ daemon_msg_err(SOCKET sockctrl_in, uint32 plen) } else { - if (sock_recv(sockctrl_in, remote_errbuf, plen, + if (sock_recv(sockctrl_in, ssl, remote_errbuf, plen, SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE) == -1) { @@ -973,7 +978,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) int status; struct rpcap_auth auth; // RPCAP authentication header - status = rpcapd_recv(pars->sockctrl_in, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf); + status = rpcapd_recv(pars->sockctrl_in, pars->ssl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf); if (status == -1) { return -1; @@ -1009,7 +1014,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) PCAP_ERRBUF_SIZE, errno, "malloc() failed"); goto error; } - status = rpcapd_recv(pars->sockctrl_in, username, usernamelen, &plen, errmsgbuf); + status = rpcapd_recv(pars->sockctrl_in, pars->ssl, username, usernamelen, &plen, errmsgbuf); if (status == -1) { free(username); @@ -1031,7 +1036,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) free(username); goto error; } - status = rpcapd_recv(pars->sockctrl_in, passwd, passwdlen, &plen, errmsgbuf); + status = rpcapd_recv(pars->sockctrl_in, pars->ssl, passwd, passwdlen, &plen, errmsgbuf); if (status == -1) { free(username); @@ -1054,7 +1059,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) // free(username); free(passwd); - if (rpcap_senderror(pars->sockctrl_out, + if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version, PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1) { @@ -1091,7 +1096,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) rpcap_createhdr(&header, pars->protocol_version, RPCAP_MSG_AUTH_REPLY, 0, 0); // Send the ok message back - if (sock_send(pars->sockctrl_out, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) + if (sock_send(pars->sockctrl_out, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) { // That failed; log a messsage and give up. rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); @@ -1099,7 +1104,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) } // Check if all the data has been read; if not, discard the data in excess - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) { return -1; } @@ -1107,7 +1112,7 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) return 0; error: - if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version, + if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version, PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1) { // That failed; log a message and give up. @@ -1117,7 +1122,7 @@ error: error_noreply: // Check if all the data has been read; if not, discard the data in excess - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) { return -1; } @@ -1262,7 +1267,7 @@ daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen) uint16 nif = 0; // counts the number of interface listed // Discard the rest of the message; there shouldn't be any payload. - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) { // Network error. return -1; @@ -1274,7 +1279,7 @@ daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen) if (alldevs == NULL) { - if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version, + if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version, PCAP_ERR_NOREMOTEIF, "No interfaces found! Make sure libpcap/WinPcap is properly installed" " and you have the right to access to the remote device.", @@ -1428,7 +1433,7 @@ daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen) pcap_freealldevs(alldevs); // Send a final command that says "now send it!" - if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + if (sock_send(pars->sockctrl_out, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) { rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); return -1; @@ -1440,7 +1445,7 @@ error: if (alldevs) pcap_freealldevs(alldevs); - if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version, + if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version, PCAP_ERR_FINDALLIF, errmsgbuf, errbuf) == -1) { rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); @@ -1470,7 +1475,7 @@ daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_ goto error; } - nread = sock_recv(pars->sockctrl_in, source, plen, + nread = sock_recv(pars->sockctrl_in, pars->ssl, source, plen, SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) { @@ -1513,7 +1518,7 @@ daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_ pcap_close(fp); // Send the reply. - if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + if (sock_send(pars->sockctrl_out, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) { rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); return -1; @@ -1521,7 +1526,7 @@ daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_ return 0; error: - if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version, + if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version, PCAP_ERR_OPEN, errmsgbuf, errbuf) == -1) { // That failed; log a message and give up. @@ -1530,7 +1535,7 @@ error: } // Check if all the data has been read; if not, discard the data in excess - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) { return -1; } @@ -1542,7 +1547,7 @@ error: to discard excess data in the message, if present) */ static int -daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_handle *threaddata, char *source, struct session **sessionp, struct rpcap_sampling *samp_param _U_) +daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_handle *threaddata, 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 @@ -1572,7 +1577,7 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h addrinfo = NULL; - status = rpcapd_recv(pars->sockctrl_in, (char *) &startcapreq, + status = rpcapd_recv(pars->sockctrl_in, pars->ssl, (char *) &startcapreq, sizeof(struct rpcap_startcapreq), &plen, errmsgbuf); if (status == -1) { @@ -1585,6 +1590,15 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h startcapreq.flags = ntohs(startcapreq.flags); + // Check that the client does not ask for UDP is the server has been asked + // to enforce encryption, as SSL is not supported yet with UDP: + if (uses_ssl && (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM)) + { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SSL not supported with UDP forward of remote packets"); + goto error; + } + // Create a session structure session = malloc(sizeof(struct session)); if (session == NULL) @@ -1593,6 +1607,8 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h goto error; } + session->ctrl_ssl = session->data_ssl = NULL; + // Open the selected device if ((session->fp = pcap_open_live(source, ntohl(startcapreq.snaplen), @@ -1687,10 +1703,11 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h // Needed to send an error on the ctrl connection session->sockctrl_out = pars->sockctrl_out; + session->ctrl_ssl = pars->ssl; session->protocol_version = pars->protocol_version; // Now I can set the filter - ret = daemon_unpackapplyfilter(pars->sockctrl_in, session, &plen, errmsgbuf); + ret = daemon_unpackapplyfilter(pars->sockctrl_in, pars->ssl, session, &plen, errmsgbuf); if (ret == -1) { // Fatal error. A message has been logged; just give up. @@ -1725,7 +1742,7 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h startcapreply->portdata = htons(port); } - if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + if (sock_send(pars->sockctrl_out, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) { // That failed; log a message and give up. rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); @@ -1754,6 +1771,22 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h sockdata = socktemp; } + SSL *ssl = NULL; + if (uses_ssl) + { +#ifdef HAVE_OPENSSL + /* In both active or passive cases, wait for the client to initiate the + * TLS handshake. Yes during that time the control socket will not be + * served, but the same was true from the above call to accept(). */ + ssl = ssl_promotion(1, sockdata, errbuf, PCAP_ERRBUF_SIZE); + if (! ssl) + { + rpcapd_log(LOGPRIO_ERROR, "TLS handshake failed: %s", errbuf); + goto error; + } +#endif + } + session->data_ssl = ssl; session->sockdata = sockdata; // Now we have to create a new thread to receive packets @@ -1784,7 +1817,7 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, struct thread_h threaddata->have_thread = 1; // Check if all the data has been read; if not, discard the data in excess - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) goto fatal_error; *sessionp = session; @@ -1822,10 +1855,16 @@ error: { if (session->fp) pcap_close(session->fp); +#ifdef HAVE_OPENSSL + if (session->ctrl_ssl) + SSL_free(session->ctrl_ssl); + if (session->data_ssl) + SSL_free(session->data_ssl); +#endif free(session); } - if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version, + if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version, PCAP_ERR_STARTCAPTURE, errmsgbuf, errbuf) == -1) { // That failed; log a message and give up. @@ -1834,7 +1873,7 @@ error: } // Check if all the data has been read; if not, discard the data in excess - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) { // Network error. return -1; @@ -1894,6 +1933,12 @@ fatal_error: { if (session->fp) pcap_close(session->fp); +#ifdef HAVE_OPENSSL + if (session->ctrl_ssl) + SSL_free(session->ctrl_ssl); + if (session->data_ssl) + SSL_free(session->data_ssl); +#endif free(session); } @@ -1940,18 +1985,13 @@ daemon_msg_endcap_req(struct daemon_slpars *pars, struct session *session, struc #endif threaddata->have_thread = 0; } - if (session->sockdata) - { - sock_close(session->sockdata, NULL, 0); - session->sockdata = 0; - } - pcap_close(session->fp); + session_close(session); rpcap_createhdr(&header, pars->protocol_version, RPCAP_MSG_ENDCAP_REPLY, 0, 0); - if (sock_send(pars->sockctrl_out, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) + if (sock_send(pars->sockctrl_out, pars->ssl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) { // That failed; log a message and give up. rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); @@ -1962,7 +2002,7 @@ daemon_msg_endcap_req(struct daemon_slpars *pars, struct session *session, struc } static int -daemon_unpackapplyfilter(SOCKET sockctrl_in, struct session *session, uint32 *plenp, char *errmsgbuf) +daemon_unpackapplyfilter(SOCKET sockctrl_in, SSL *ctrl_ssl, struct session *session, uint32 *plenp, char *errmsgbuf) { int status; struct rpcap_filter filter; @@ -1971,7 +2011,7 @@ daemon_unpackapplyfilter(SOCKET sockctrl_in, struct session *session, uint32 *pl struct bpf_program bf_prog; unsigned int i; - status = rpcapd_recv(sockctrl_in, (char *) &filter, + status = rpcapd_recv(sockctrl_in, ctrl_ssl, (char *) &filter, sizeof(struct rpcap_filter), plenp, errmsgbuf); if (status == -1) { @@ -2002,7 +2042,7 @@ daemon_unpackapplyfilter(SOCKET sockctrl_in, struct session *session, uint32 *pl for (i = 0; i < bf_prog.bf_len; i++) { - status = rpcapd_recv(sockctrl_in, (char *) &insn, + status = rpcapd_recv(sockctrl_in, ctrl_ssl, (char *) &insn, sizeof(struct rpcap_filterbpf_insn), plenp, errmsgbuf); if (status == -1) { @@ -2047,7 +2087,7 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session, int ret; // status of daemon_unpackapplyfilter() struct rpcap_header header; // keeps the answer to the updatefilter command - ret = daemon_unpackapplyfilter(pars->sockctrl_in, session, &plen, errmsgbuf); + ret = daemon_unpackapplyfilter(pars->sockctrl_in, pars->ssl, session, &plen, errmsgbuf); if (ret == -1) { // Fatal error. A message has been logged; just give up. @@ -2060,7 +2100,7 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session, } // Check if all the data has been read; if not, discard the data in excess - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) { // Network error. return -1; @@ -2070,7 +2110,7 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session, rpcap_createhdr(&header, pars->protocol_version, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0); - if (sock_send(pars->sockctrl_out, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE)) + if (sock_send(pars->sockctrl_out, pars->ssl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE)) { // That failed; log a messsage and give up. rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); @@ -2080,11 +2120,11 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session, return 0; error: - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) { return -1; } - rpcap_senderror(pars->sockctrl_out, pars->protocol_version, + rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version, PCAP_ERR_UPDATEFILTER, errmsgbuf, NULL); return 0; @@ -2102,7 +2142,7 @@ daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap struct rpcap_sampling rpcap_samp; int status; - status = rpcapd_recv(pars->sockctrl_in, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf); + status = rpcapd_recv(pars->sockctrl_in, pars->ssl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf); if (status == -1) { return -1; @@ -2120,14 +2160,14 @@ daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap rpcap_createhdr(&header, pars->protocol_version, RPCAP_MSG_SETSAMPLING_REPLY, 0, 0); - if (sock_send(pars->sockctrl_out, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) + if (sock_send(pars->sockctrl_out, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) { // That failed; log a messsage and give up. rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); return -1; } - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) { return -1; } @@ -2135,7 +2175,7 @@ daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap return 0; error: - if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version, + if (rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version, PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1) { // That failed; log a message and give up. @@ -2144,7 +2184,7 @@ error: } // Check if all the data has been read; if not, discard the data in excess - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) { return -1; } @@ -2162,7 +2202,7 @@ daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32 struct rpcap_stats *netstats; // statistics sent on the network // Checks that the header does not contain other data; if so, discard it - if (rpcapd_discard(pars->sockctrl_in, plen) == -1) + if (rpcapd_discard(pars->sockctrl_in, pars->ssl, plen) == -1) { // Network error. return -1; @@ -2206,7 +2246,7 @@ daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32 } // Send the packet - if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + if (sock_send(pars->sockctrl_out, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) { rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); return -1; @@ -2215,7 +2255,7 @@ daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32 return 0; error: - rpcap_senderror(pars->sockctrl_out, pars->protocol_version, + rpcap_senderror(pars->sockctrl_out, pars->ssl, pars->protocol_version, PCAP_ERR_GETSTATS, errmsgbuf, NULL); return 0; } @@ -2376,7 +2416,7 @@ daemon_thrdatamain(void *ptr) // Send the packet // If the client dropped the connection, don't report an // error, just quit. - status = sock_send(session->sockdata, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE); + status = sock_send(session->sockdata, session->data_ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE); if (status < 0) { if (status == -1) @@ -2401,14 +2441,13 @@ daemon_thrdatamain(void *ptr) if (retval == -1) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp)); - rpcap_senderror(session->sockctrl_out, session->protocol_version, + rpcap_senderror(session->sockctrl_out, session->ctrl_ssl, session->protocol_version, PCAP_ERR_READEX, errbuf, NULL); goto error; } error: - closesocket(session->sockdata); - session->sockdata = 0; + session_close(session); free(sendbuf); @@ -2497,12 +2536,12 @@ void sleep_secs(int secs) * Read the header of a message. */ static int -rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp) +rpcapd_recv_msg_header(SOCKET sock, SSL *ssl, struct rpcap_header *headerp) { int nread; char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors - nread = sock_recv(sock, (char *) headerp, sizeof(struct rpcap_header), + nread = sock_recv(sock, ssl, (char *) headerp, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR, errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) { @@ -2529,7 +2568,7 @@ rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp) * error. */ static int -rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf) +rpcapd_recv(SOCKET sock, SSL *ssl, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf) { int nread; char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors @@ -2540,7 +2579,7 @@ rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsg pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message payload is too short"); return -2; } - nread = sock_recv(sock, buffer, toread, + nread = sock_recv(sock, ssl, buffer, toread, SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE); if (nread == -1) { @@ -2558,13 +2597,13 @@ rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsg * error. */ static int -rpcapd_discard(SOCKET sock, uint32 len) +rpcapd_discard(SOCKET sock, SSL *ssl, uint32 len) { char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed if (len != 0) { - if (sock_discard(sock, len, errbuf, PCAP_ERRBUF_SIZE) == -1) + if (sock_discard(sock, ssl, len, errbuf, PCAP_ERRBUF_SIZE) == -1) { // Network error. rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); @@ -2573,3 +2612,27 @@ rpcapd_discard(SOCKET sock, uint32 len) } return 0; } + +/* + * Close the socket associated with the session, the optional SSL handle, + * and the underlying packet capture handle. We of course do not touch + * the controlling socket that's also copied into the session. + */ +static void session_close(struct session *session) +{ +#ifdef HAVE_OPENSSL + if (session->data_ssl) + { + SSL_free(session->data_ssl); // Must happen *before* the socket is closed + session->data_ssl = NULL; + } +#endif + + if (session->sockdata) + { + sock_close(session->sockdata, NULL, 0); + session->sockdata = 0; + } + + pcap_close(session->fp); +} |