aboutsummaryrefslogtreecommitdiff
path: root/pcap-rpcap.c
diff options
context:
space:
mode:
Diffstat (limited to 'pcap-rpcap.c')
-rw-r--r--pcap-rpcap.c162
1 files changed, 142 insertions, 20 deletions
diff --git a/pcap-rpcap.c b/pcap-rpcap.c
index a2612e99..062f1107 100644
--- a/pcap-rpcap.c
+++ b/pcap-rpcap.c
@@ -36,11 +36,13 @@
#endif
#include "ftmacros.h"
+#include "diag-control.h"
#include <string.h> /* for strlen(), ... */
#include <stdlib.h> /* for malloc(), free(), ... */
#include <stdarg.h> /* for functions with variable number of arguments */
#include <errno.h> /* for the errno variable */
+#include <limits.h> /* for INT_MAX */
#include "sockutils.h"
#include "pcap-int.h"
#include "rpcap-protocol.h"
@@ -644,6 +646,21 @@ static int pcap_read_rpcap(pcap_t *p, int cnt, pcap_handler callback, u_char *us
}
}
+ /*
+ * This can conceivably process more than INT_MAX packets,
+ * which would overflow the packet count, causing it either
+ * to look like a negative number, and thus cause us to
+ * return a value that looks like an error, or overflow
+ * back into positive territory, and thus cause us to
+ * return a too-low count.
+ *
+ * Therefore, if the packet count is unlimited, we clip
+ * it at INT_MAX; this routine is not expected to
+ * process packets indefinitely, so that's not an issue.
+ */
+ if (PACKET_COUNT_IS_UNLIMITED(cnt))
+ cnt = INT_MAX;
+
while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt))
{
/*
@@ -1003,11 +1020,10 @@ rpcap_remoteact_getsock(const char *host, int *error, char *errbuf)
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- retval = getaddrinfo(host, "0", &hints, &addrinfo);
+ retval = sock_initaddress(host, "0", &hints, &addrinfo, errbuf,
+ PCAP_ERRBUF_SIZE);
if (retval != 0)
{
- snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s",
- gai_strerror(retval));
*error = 1;
return NULL;
}
@@ -1060,7 +1076,7 @@ static int pcap_startcapture_remote(pcap_t *fp)
struct pcap_rpcap *pr = fp->priv; /* structure used when doing a remote live capture */
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 */
- char portdata[PCAP_BUF_SIZE]; /* temp variable needed to keep the network port for the data connection */
+ uint16 portdata = 0; /* temp variable needed to keep the network port for the data connection */
uint32 plen;
int active = 0; /* '1' if we're in active mode */
struct activehosts *temp; /* temp var needed to scan the host list chain, to detect if we're in active mode */
@@ -1073,6 +1089,8 @@ static int pcap_startcapture_remote(pcap_t *fp)
struct sockaddr_storage saddr; /* temp, needed to retrieve the network data port chosen on the local machine */
socklen_t saddrlen; /* temp, needed to retrieve the network data port chosen on the local machine */
int ai_family; /* temp, keeps the address family used by the control connection */
+ struct sockaddr_in *sin4;
+ struct sockaddr_in6 *sin6;
/* RPCAP-related variables*/
struct rpcap_header header; /* header of the RPCAP packet */
@@ -1086,7 +1104,9 @@ static int pcap_startcapture_remote(pcap_t *fp)
uint32 server_sockbufsize;
// Take the opportunity to clear pr->data_ssl before any goto error,
- // as it seems pr->priv is not zeroed after its malloced.
+ // as it seems p->priv is not zeroed after its malloced.
+ // XXX - it now should be, as it's allocated by pcap_alloc_pcap_t(),
+ // which does a calloc().
pr->data_ssl = NULL;
/*
@@ -1171,11 +1191,22 @@ static int pcap_startcapture_remote(pcap_t *fp)
goto error_nodiscard;
}
- /* Get the local port the system picked up */
- if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL,
- 0, portdata, sizeof(portdata), NI_NUMERICSERV))
- {
- sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE);
+ switch (saddr.ss_family) {
+
+ case AF_INET:
+ sin4 = (struct sockaddr_in *)&saddr;
+ portdata = sin4->sin_port;
+ break;
+
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)&saddr;
+ portdata = sin6->sin6_port;
+ break;
+
+ default:
+ snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
+ "Local address has unknown address family %u",
+ saddr.ss_family);
goto error_nodiscard;
}
}
@@ -1208,8 +1239,7 @@ static int pcap_startcapture_remote(pcap_t *fp)
/* portdata on the openreq is meaningful only if we're in active mode */
if ((active) || (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP))
{
- sscanf(portdata, "%d", (int *)&(startcapreq->portdata)); /* cast to avoid a compiler warning */
- startcapreq->portdata = htons(startcapreq->portdata);
+ startcapreq->portdata = portdata;
}
startcapreq->snaplen = htonl(fp->snapshot);
@@ -1258,13 +1288,15 @@ static int pcap_startcapture_remote(pcap_t *fp)
{
if (!active)
{
+ char portstring[PCAP_BUF_SIZE];
+
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = ai_family; /* Use the same address family of the control socket */
hints.ai_socktype = (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM;
- snprintf(portdata, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata));
+ snprintf(portstring, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata));
/* Let's the server pick up a free network port for us */
- if (sock_initaddress(host, portdata, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
+ if (sock_initaddress(host, portstring, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
goto error;
if ((sockdata = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
@@ -2110,6 +2142,79 @@ novers:
return -1;
}
+/* non-alphanumeric unreserved characters plus sub-delims (RFC3986) */
+static const char userinfo_allowed_symbols[] = "-._~!&'()*+,;=";
+
+/*
+ * This function is a thin wrapper around rpcap_doauth which will use an auth
+ * struct created from a username and password parsed out of the userinfo
+ * portion of a URI.
+ */
+static int rpcap_doauth_userinfo(SOCKET sockctrl, SSL *ssl, uint8 *ver, const char *userinfo, char *errbuf)
+{
+ struct pcap_rmtauth auth;
+ const char *ptr;
+ char *buf, username[256], password[256];
+
+ auth.type = RPCAP_RMTAUTH_PWD;
+ auth.username = username;
+ auth.password = password;
+ buf = username;
+
+ username[0] = password[0] = '\0';
+
+ if ((ptr = userinfo) != NULL)
+ {
+ for (int pos = -1; (buf[++pos] = *ptr) != '\0'; ++ptr)
+ {
+ /* handle %xx encoded characters */
+ if (*ptr == '%')
+ {
+ /* the pedantic thing to do here would be throwing an error on
+ * a sequence like `%hi', however a lot of common tools just accept
+ * such malarkey, so... probably it will be fine? */
+ if (sscanf(ptr, "%%%02hhx", (unsigned char *)(buf+pos)) == 1)
+ ptr += 2;
+ /* other implementations aside, rejecting null bytes seems prudent */
+ if (buf[pos] == '\0')
+ {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid escape `%%00` in userinfo");
+ return -1;
+ }
+ }
+ else if (*ptr == ':' && buf == username)
+ {
+ /* terminate username string and switch to password string */
+ buf[pos] = '\0';
+ buf = password;
+ pos = -1;
+ }
+ /* constrain to characters allowed by RFC3986 */
+ else if (*ptr >= 'A' && *ptr <= 'Z')
+ continue;
+ else if (*ptr >= 'a' && *ptr <= 'z')
+ continue;
+ else if (*ptr >= '0' && *ptr <= '9')
+ continue;
+ else if (*ptr < ' ' || *ptr > '~')
+ {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid character `\\%o` in userinfo", *ptr);
+ return -1;
+ }
+ else if (strchr(userinfo_allowed_symbols, *ptr) == NULL)
+ {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid character `%c` in userinfo", *ptr);
+ return -1;
+ }
+ }
+
+ return rpcap_doauth(sockctrl, ssl, ver, &auth, errbuf);
+ }
+
+ return rpcap_doauth(sockctrl, ssl, ver, NULL, errbuf);
+}
+
+
/* We don't currently support non-blocking mode. */
static int
pcap_getnonblock_rpcap(pcap_t *p)
@@ -2134,15 +2239,18 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
char *iface, char *errbuf)
{
int type;
+ int auth_result;
+ char userinfo[512]; /* 256 characters each for username and password */
struct activehosts *activeconn; /* active connection, if there is one */
int error; /* 1 if rpcap_remoteact_getsock got an error */
+ userinfo[0] = '\0';
/*
* Determine the type of the source (NULL, file, local, remote).
* You must have a valid source string even if we're in active mode,
* because otherwise the call to the following function will fail.
*/
- if (pcap_parsesrcstr_ex(source, &type, host, port, iface, uses_sslp,
+ if (pcap_parsesrcstr_ex(source, &type, userinfo, host, port, iface, uses_sslp,
errbuf) == -1)
return -1;
@@ -2247,8 +2355,18 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
#endif
}
- if (rpcap_doauth(*sockctrlp, *sslp, protocol_versionp, auth,
- errbuf) == -1)
+ if (auth == NULL && *userinfo != '\0')
+ {
+ auth_result = rpcap_doauth_userinfo(*sockctrlp, *sslp, protocol_versionp,
+ userinfo, errbuf);
+ }
+ else
+ {
+ auth_result = rpcap_doauth(*sockctrlp, *sslp, protocol_versionp, auth,
+ errbuf);
+ }
+
+ if (auth_result == -1)
{
#ifdef HAVE_OPENSSL
if (*sslp)
@@ -2592,7 +2710,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
/* Create the new device identifier */
if (pcap_createsrcstr_ex(tmpstring2, PCAP_SRC_IFREMOTE,
- host, port, tmpstring, uses_ssl, errbuf) == -1)
+ NULL, host, port, tmpstring, uses_ssl, errbuf) == -1)
goto error;
dev->name = strdup(tmpstring2);
@@ -2992,10 +3110,10 @@ int pcap_remoteact_close(const char *host, char *errbuf)
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- retval = getaddrinfo(host, "0", &hints, &addrinfo);
+ retval = sock_initaddress(host, "0", &hints, &addrinfo, errbuf,
+ PCAP_ERRBUF_SIZE);
if (retval != 0)
{
- snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval));
return -1;
}
@@ -3352,7 +3470,9 @@ static void rpcap_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen, char *remote_e
PCAP_ERRBUF_SIZE) == -1)
{
// Network error.
+ DIAG_OFF_FORMAT_TRUNCATION
snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf);
+ DIAG_ON_FORMAT_TRUNCATION
return;
}
@@ -3387,7 +3507,9 @@ static void rpcap_msg_err(SOCKET sockctrl, SSL *ssl, uint32 plen, char *remote_e
PCAP_ERRBUF_SIZE) == -1)
{
// Network error.
+ DIAG_OFF_FORMAT_TRUNCATION
snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf);
+ DIAG_ON_FORMAT_TRUNCATION
return;
}