194960e5delphij/*
294960e5delphij * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
394960e5delphij * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California)
494960e5delphij * All rights reserved.
594960e5delphij *
694960e5delphij * Redistribution and use in source and binary forms, with or without
794960e5delphij * modification, are permitted provided that the following conditions
894960e5delphij * are met:
994960e5delphij *
1094960e5delphij * 1. Redistributions of source code must retain the above copyright
1194960e5delphij * notice, this list of conditions and the following disclaimer.
1294960e5delphij * 2. Redistributions in binary form must reproduce the above copyright
1394960e5delphij * notice, this list of conditions and the following disclaimer in the
1494960e5delphij * documentation and/or other materials provided with the distribution.
1594960e5delphij * 3. Neither the name of the Politecnico di Torino, CACE Technologies
1694960e5delphij * nor the names of its contributors may be used to endorse or promote
1794960e5delphij * products derived from this software without specific prior written
1894960e5delphij * permission.
1994960e5delphij *
2094960e5delphij * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2194960e5delphij * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2294960e5delphij * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2394960e5delphij * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2494960e5delphij * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2594960e5delphij * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2694960e5delphij * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2794960e5delphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2894960e5delphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2994960e5delphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3094960e5delphij * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3194960e5delphij *
3294960e5delphij */
3394960e5delphij
3494960e5delphij#ifdef HAVE_CONFIG_H
3519bb0b8hselasky#include <config.h>
3694960e5delphij#endif
3794960e5delphij
3819bb0b8hselasky#include "ftmacros.h"
3919bb0b8hselasky
4094960e5delphij#include <string.h>		/* for strlen(), ... */
4194960e5delphij#include <stdlib.h>		/* for malloc(), free(), ... */
4294960e5delphij#include <stdarg.h>		/* for functions with variable number of arguments */
4394960e5delphij#include <errno.h>		/* for the errno variable */
4419bb0b8hselasky#include "sockutils.h"
4594960e5delphij#include "pcap-int.h"
4619bb0b8hselasky#include "rpcap-protocol.h"
4794960e5delphij#include "pcap-rpcap.h"
4894960e5delphij
4994960e5delphij/*
5019bb0b8hselasky * This file contains the pcap module for capturing from a remote machine's
5119bb0b8hselasky * interfaces using the RPCAP protocol.
5294960e5delphij *
5319bb0b8hselasky * WARNING: All the RPCAP functions that are allowed to return a buffer
5419bb0b8hselasky * containing the error description can return max PCAP_ERRBUF_SIZE characters.
5594960e5delphij * However there is no guarantees that the string will be zero-terminated.
5619bb0b8hselasky * Best practice is to define the errbuf variable as a char of size
5719bb0b8hselasky * 'PCAP_ERRBUF_SIZE+1' and to insert manually a NULL character at the end
5819bb0b8hselasky * of the buffer. This will guarantee that no buffer overflows occur even
5919bb0b8hselasky * if we use the printf() to show the error on the screen.
6019bb0b8hselasky *
6119bb0b8hselasky * XXX - actually, null-terminating the error string is part of the
6219bb0b8hselasky * contract for the pcap API; if there's any place in the pcap code
6319bb0b8hselasky * that doesn't guarantee null-termination, even at the expense of
6419bb0b8hselasky * cutting the message short, that's a bug and needs to be fixed.
6594960e5delphij */
6694960e5delphij
6719bb0b8hselasky#define PCAP_STATS_STANDARD	0	/* Used by pcap_stats_rpcap to see if we want standard or extended statistics */
6819bb0b8hselasky#ifdef _WIN32
6919bb0b8hselasky#define PCAP_STATS_EX		1	/* Used by pcap_stats_rpcap to see if we want standard or extended statistics */
7019bb0b8hselasky#endif
7119bb0b8hselasky
7219bb0b8hselasky/*
7319bb0b8hselasky * \brief Keeps a list of all the opened connections in the active mode.
7419bb0b8hselasky *
7519bb0b8hselasky * This structure defines a linked list of items that are needed to keep the info required to
7619bb0b8hselasky * manage the active mode.
7719bb0b8hselasky * In other words, when a new connection in active mode starts, this structure is updated so that
7819bb0b8hselasky * it reflects the list of active mode connections currently opened.
7919bb0b8hselasky * This structure is required by findalldevs() and open_remote() to see if they have to open a new
8019bb0b8hselasky * control connection toward the host, or they already have a control connection in place.
8119bb0b8hselasky */
8219bb0b8hselaskystruct activehosts
8319bb0b8hselasky{
8419bb0b8hselasky	struct sockaddr_storage host;
8519bb0b8hselasky	SOCKET sockctrl;
8619bb0b8hselasky	uint8 protocol_version;
8719bb0b8hselasky	struct activehosts *next;
8819bb0b8hselasky};
8994960e5delphij
9094960e5delphij/* Keeps a list of all the opened connections in the active mode. */
9119bb0b8hselaskystatic struct activehosts *activeHosts;
9294960e5delphij
9394960e5delphij/*
9419bb0b8hselasky * Keeps the main socket identifier when we want to accept a new remote
9519bb0b8hselasky * connection (active mode only).
9619bb0b8hselasky * See the documentation of pcap_remoteact_accept() and
9719bb0b8hselasky * pcap_remoteact_cleanup() for more details.
9894960e5delphij */
9919bb0b8hselaskystatic SOCKET sockmain;
10094960e5delphij
10119bb0b8hselasky/*
10219bb0b8hselasky * Private data for capturing remotely using the rpcap protocol.
10319bb0b8hselasky */
10419bb0b8hselaskystruct pcap_rpcap {
10519bb0b8hselasky	/*
10619bb0b8hselasky	 * This is '1' if we're the network client; it is needed by several
10719bb0b8hselasky	 * functions (such as pcap_setfilter()) to know whether they have
10819bb0b8hselasky	 * to use the socket or have to open the local adapter.
10919bb0b8hselasky	 */
11019bb0b8hselasky	int rmt_clientside;
11119bb0b8hselasky
11219bb0b8hselasky	SOCKET rmt_sockctrl;		/* socket ID of the socket used for the control connection */
11319bb0b8hselasky	SOCKET rmt_sockdata;		/* socket ID of the socket used for the data connection */
11419bb0b8hselasky	int rmt_flags;			/* we have to save flags, since they are passed by the pcap_open_live(), but they are used by the pcap_startcapture() */
11519bb0b8hselasky	int rmt_capstarted;		/* 'true' if the capture is already started (needed to knoe if we have to call the pcap_startcapture() */
11619bb0b8hselasky	char *currentfilter;		/* Pointer to a buffer (allocated at run-time) that stores the current filter. Needed when flag PCAP_OPENFLAG_NOCAPTURE_RPCAP is turned on. */
11719bb0b8hselasky
11819bb0b8hselasky	uint8 protocol_version;		/* negotiated protocol version */
11919bb0b8hselasky
12019bb0b8hselasky	unsigned int TotNetDrops;	/* keeps the number of packets that have been dropped by the network */
12119bb0b8hselasky
12219bb0b8hselasky	/*
12319bb0b8hselasky	 * This keeps the number of packets that have been received by the
12419bb0b8hselasky	 * application.
12519bb0b8hselasky	 *
12619bb0b8hselasky	 * Packets dropped by the kernel buffer are not counted in this
12719bb0b8hselasky	 * variable. It is always equal to (TotAccepted - TotDrops),
12819bb0b8hselasky	 * except for the case of remote capture, in which we have also
12919bb0b8hselasky	 * packets in flight, i.e. that have been transmitted by the remote
13019bb0b8hselasky	 * host, but that have not been received (yet) from the client.
13119bb0b8hselasky	 * In this case, (TotAccepted - TotDrops - TotNetDrops) gives a
13219bb0b8hselasky	 * wrong result, since this number does not corresponds always to
13319bb0b8hselasky	 * the number of packet received by the application. For this reason,
13419bb0b8hselasky	 * in the remote capture we need another variable that takes into
13519bb0b8hselasky	 * account of the number of packets actually received by the
13619bb0b8hselasky	 * application.
13719bb0b8hselasky	 */
13819bb0b8hselasky	unsigned int TotCapt;
13919bb0b8hselasky
14019bb0b8hselasky	struct pcap_stat stat;
14119bb0b8hselasky	/* XXX */
14219bb0b8hselasky	struct pcap *next;		/* list of open pcaps that need stuff cleared on close */
14394960e5delphij};
14494960e5delphij
14594960e5delphij/****************************************************
14694960e5delphij *                                                  *
14794960e5delphij * Locally defined functions                        *
14894960e5delphij *                                                  *
14994960e5delphij ****************************************************/
15019bb0b8hselaskystatic struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int mode);
15194960e5delphijstatic int pcap_pack_bpffilter(pcap_t *fp, char *sendbuf, int *sendbufidx, struct bpf_program *prog);
15294960e5delphijstatic int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog);
15394960e5delphijstatic int pcap_updatefilter_remote(pcap_t *fp, struct bpf_program *prog);
15419bb0b8hselaskystatic void pcap_save_current_filter_rpcap(pcap_t *fp, const char *filter);
15519bb0b8hselaskystatic int pcap_setfilter_rpcap(pcap_t *fp, struct bpf_program *prog);
15619bb0b8hselaskystatic int pcap_setsampling_remote(pcap_t *fp);
15719bb0b8hselaskystatic int pcap_startcapture_remote(pcap_t *fp);
15819bb0b8hselaskystatic int rpcap_recv_msg_header(SOCKET sock, struct rpcap_header *header, char *errbuf);
15919bb0b8hselaskystatic int rpcap_check_msg_ver(SOCKET sock, uint8 expected_ver, struct rpcap_header *header, char *errbuf);
16019bb0b8hselaskystatic int rpcap_check_msg_type(SOCKET sock, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf);
16119bb0b8hselaskystatic int rpcap_process_msg_header(SOCKET sock, uint8 ver, uint8 request_type, struct rpcap_header *header, char *errbuf);
16219bb0b8hselaskystatic int rpcap_recv(SOCKET sock, void *buffer, size_t toread, uint32 *plen, char *errbuf);
16319bb0b8hselaskystatic void rpcap_msg_err(SOCKET sockctrl, uint32 plen, char *remote_errbuf);
16419bb0b8hselaskystatic int rpcap_discard(SOCKET sock, uint32 len, char *errbuf);
16519bb0b8hselaskystatic int rpcap_read_packet_msg(SOCKET sock, pcap_t *p, size_t size);
16694960e5delphij
16794960e5delphij/****************************************************
16894960e5delphij *                                                  *
16994960e5delphij * Function bodies                                  *
17094960e5delphij *                                                  *
17194960e5delphij ****************************************************/
17294960e5delphij
17394960e5delphij/*
17419bb0b8hselasky * This function translates (i.e. de-serializes) a 'rpcap_sockaddr'
17519bb0b8hselasky * structure from the network byte order to a 'sockaddr_in" or
17619bb0b8hselasky * 'sockaddr_in6' structure in the host byte order.
17719bb0b8hselasky *
17819bb0b8hselasky * It accepts an 'rpcap_sockaddr' structure as it is received from the
17919bb0b8hselasky * network, and checks the address family field against various values
18019bb0b8hselasky * to see whether it looks like an IPv4 address, an IPv6 address, or
18119bb0b8hselasky * neither of those.  It checks for multiple values in order to try
18219bb0b8hselasky * to handle older rpcap daemons that sent the native OS's 'sockaddr_in'
18319bb0b8hselasky * or 'sockaddr_in6' structures over the wire with some members
18419bb0b8hselasky * byte-swapped, and to handle the fact that AF_INET6 has different
18519bb0b8hselasky * values on different OSes.
18619bb0b8hselasky *
18719bb0b8hselasky * For IPv4 addresses, it converts the address family to host byte
18819bb0b8hselasky * order from network byte order and puts it into the structure,
18919bb0b8hselasky * sets the length if a sockaddr structure has a length, converts the
19019bb0b8hselasky * port number to host byte order from network byte order and puts
19119bb0b8hselasky * it into the structure, copies over the IPv4 address, and zeroes
19219bb0b8hselasky * out the zero padding.
19319bb0b8hselasky *
19419bb0b8hselasky * For IPv6 addresses, it converts the address family to host byte
19519bb0b8hselasky * order from network byte order and puts it into the structure,
19619bb0b8hselasky * sets the length if a sockaddr structure has a length, converts the
19719bb0b8hselasky * port number and flow information to host byte order from network
19819bb0b8hselasky * byte order and puts them into the structure, copies over the IPv6
19919bb0b8hselasky * address, and converts the scope ID to host byte order from network
20019bb0b8hselasky * byte order and puts it into the structure.
20119bb0b8hselasky *
20219bb0b8hselasky * The function will allocate the 'sockaddrout' variable according to the
20319bb0b8hselasky * address family in use. In case the address does not belong to the
20419bb0b8hselasky * AF_INET nor AF_INET6 families, 'sockaddrout' is not allocated and a
20519bb0b8hselasky * NULL pointer is returned.  This usually happens because that address
20619bb0b8hselasky * does not exist on the other host, or is of an address family other
20719bb0b8hselasky * than AF_INET or AF_INET6, so the RPCAP daemon sent a 'sockaddr_storage'
20819bb0b8hselasky * structure containing all 'zero' values.
20919bb0b8hselasky *
21019bb0b8hselasky * Older RPCAPDs sent the addresses over the wire in the OS's native
21119bb0b8hselasky * structure format.  For most OSes, this looks like the over-the-wire
21219bb0b8hselasky * format, but might have a different value for AF_INET6 than the value
21319bb0b8hselasky * on the machine receiving the reply.  For OSes with the newer BSD-style
21419bb0b8hselasky * sockaddr structures, this has, instead of a 2-byte address family,
21519bb0b8hselasky * a 1-byte structure length followed by a 1-byte address family.  The
21619bb0b8hselasky * RPCAPD code would put the address family in network byte order before
21719bb0b8hselasky * sending it; that would set it to 0 on a little-endian machine, as
21819bb0b8hselasky * htons() of any value between 1 and 255 would result in a value > 255,
21919bb0b8hselasky * with its lower 8 bits zero, so putting that back into a 1-byte field
22019bb0b8hselasky * would set it to 0.
22119bb0b8hselasky *
22219bb0b8hselasky * Therefore, for older RPCAPDs running on an OS with newer BSD-style
22319bb0b8hselasky * sockaddr structures, the family field, if treated as a big-endian
22419bb0b8hselasky * (network byte order) 16-bit field, would be:
22519bb0b8hselasky *
22619bb0b8hselasky *	(length << 8) | family if sent by a big-endian machine
22719bb0b8hselasky *	(length << 8) if sent by a little-endian machine
22819bb0b8hselasky *
22919bb0b8hselasky * For current RPCAPDs, and for older RPCAPDs running on an OS with
23019bb0b8hselasky * older BSD-style sockaddr structures, the family field, if treated
23119bb0b8hselasky * as a big-endian 16-bit field, would just contain the family.
23219bb0b8hselasky *
23319bb0b8hselasky * \param sockaddrin: a 'rpcap_sockaddr' pointer to the variable that has
23419bb0b8hselasky * to be de-serialized.
23594960e5delphij *
23694960e5delphij * \param sockaddrout: a 'sockaddr_storage' pointer to the variable that will contain
23794960e5delphij * the de-serialized data. The structure returned can be either a 'sockaddr_in' or 'sockaddr_in6'.
23894960e5delphij * This variable will be allocated automatically inside this function.
23994960e5delphij *
24094960e5delphij * \param errbuf: a pointer to a user-allocated buffer (of size PCAP_ERRBUF_SIZE)
24194960e5delphij * that will contain the error message (in case there is one).
24294960e5delphij *
24394960e5delphij * \return '0' if everything is fine, '-1' if some errors occurred. Basically, the error
24494960e5delphij * can be only the fact that the malloc() failed to allocate memory.
24594960e5delphij * The error message is returned in the 'errbuf' variable, while the deserialized address
24694960e5delphij * is returned into the 'sockaddrout' variable.
24794960e5delphij *
24894960e5delphij * \warning This function supports only AF_INET and AF_INET6 address families.
24994960e5delphij *
25094960e5delphij * \warning The sockaddrout (if not NULL) must be deallocated by the user.
25194960e5delphij */
25219bb0b8hselasky
25319bb0b8hselasky/*
25419bb0b8hselasky * Possible IPv4 family values other than the designated over-the-wire value,
25519bb0b8hselasky * which is 2 (because everybody uses 2 for AF_INET4).
25619bb0b8hselasky */
25719bb0b8hselasky#define SOCKADDR_IN_LEN		16	/* length of struct sockaddr_in */
25819bb0b8hselasky#define SOCKADDR_IN6_LEN	28	/* length of struct sockaddr_in6 */
25919bb0b8hselasky#define NEW_BSD_AF_INET_BE	((SOCKADDR_IN_LEN << 8) | 2)
26019bb0b8hselasky#define NEW_BSD_AF_INET_LE	(SOCKADDR_IN_LEN << 8)
26119bb0b8hselasky
26219bb0b8hselasky/*
26319bb0b8hselasky * Possible IPv6 family values other than the designated over-the-wire value,
26419bb0b8hselasky * which is 23 (because that's what Windows uses, and most RPCAP servers
26519bb0b8hselasky * out there are probably running Windows, as WinPcap includes the server
26619bb0b8hselasky * but few if any UN*Xes build and ship it).
26719bb0b8hselasky *
26819bb0b8hselasky * The new BSD sockaddr structure format was in place before 4.4-Lite, so
26919bb0b8hselasky * all the free-software BSDs use it.
27019bb0b8hselasky */
27119bb0b8hselasky#define NEW_BSD_AF_INET6_BSD_BE		((SOCKADDR_IN6_LEN << 8) | 24)	/* NetBSD, OpenBSD, BSD/OS */
27219bb0b8hselasky#define NEW_BSD_AF_INET6_FREEBSD_BE	((SOCKADDR_IN6_LEN << 8) | 28)	/* FreeBSD, DragonFly BSD */
27319bb0b8hselasky#define NEW_BSD_AF_INET6_DARWIN_BE	((SOCKADDR_IN6_LEN << 8) | 30)	/* macOS, iOS, anything else Darwin-based */
27419bb0b8hselasky#define NEW_BSD_AF_INET6_LE		(SOCKADDR_IN6_LEN << 8)
27519bb0b8hselasky#define LINUX_AF_INET6			10
27619bb0b8hselasky#define HPUX_AF_INET6			22
27719bb0b8hselasky#define AIX_AF_INET6			24
27819bb0b8hselasky#define SOLARIS_AF_INET6		26
27919bb0b8hselasky
28019bb0b8hselaskystatic int
28119bb0b8hselaskyrpcap_deseraddr(struct rpcap_sockaddr *sockaddrin, struct sockaddr_storage **sockaddrout, char *errbuf)
28294960e5delphij{
28394960e5delphij	/* Warning: we support only AF_INET and AF_INET6 */
28419bb0b8hselasky	switch (ntohs(sockaddrin->family))
28594960e5delphij	{
28619bb0b8hselasky	case RPCAP_AF_INET:
28719bb0b8hselasky	case NEW_BSD_AF_INET_BE:
28819bb0b8hselasky	case NEW_BSD_AF_INET_LE:
28919bb0b8hselasky		{
29019bb0b8hselasky		struct rpcap_sockaddr_in *sockaddrin_ipv4;
29119bb0b8hselasky		struct sockaddr_in *sockaddrout_ipv4;
29294960e5delphij
29394960e5delphij		(*sockaddrout) = (struct sockaddr_storage *) malloc(sizeof(struct sockaddr_in));
29494960e5delphij		if ((*sockaddrout) == NULL)
29594960e5delphij		{
29619bb0b8hselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
29719bb0b8hselasky			    errno, "malloc() failed");
29894960e5delphij			return -1;
29994960e5delphij		}
30019bb0b8hselasky		sockaddrin_ipv4 = (struct rpcap_sockaddr_in *) sockaddrin;
30119bb0b8hselasky		sockaddrout_ipv4 = (struct sockaddr_in *) (*sockaddrout);
30219bb0b8hselasky		sockaddrout_ipv4->sin_family = AF_INET;
30319bb0b8hselasky		sockaddrout_ipv4->sin_port = ntohs(sockaddrin_ipv4->port);
30419bb0b8hselasky		memcpy(&sockaddrout_ipv4->sin_addr, &sockaddrin_ipv4->addr, sizeof(sockaddrout_ipv4->sin_addr));
30519bb0b8hselasky		memset(sockaddrout_ipv4->sin_zero, 0, sizeof(sockaddrout_ipv4->sin_zero));
30619bb0b8hselasky		break;
30719bb0b8hselasky		}
30894960e5delphij
30919bb0b8hselasky#ifdef AF_INET6
31019bb0b8hselasky	case RPCAP_AF_INET6:
31119bb0b8hselasky	case NEW_BSD_AF_INET6_BSD_BE:
31219bb0b8hselasky	case NEW_BSD_AF_INET6_FREEBSD_BE:
31319bb0b8hselasky	case NEW_BSD_AF_INET6_DARWIN_BE:
31419bb0b8hselasky	case NEW_BSD_AF_INET6_LE:
31519bb0b8hselasky	case LINUX_AF_INET6:
31619bb0b8hselasky	case HPUX_AF_INET6:
31719bb0b8hselasky	case AIX_AF_INET6:
31819bb0b8hselasky	case SOLARIS_AF_INET6:
31919bb0b8hselasky		{
32019bb0b8hselasky		struct rpcap_sockaddr_in6 *sockaddrin_ipv6;
32119bb0b8hselasky		struct sockaddr_in6 *sockaddrout_ipv6;
32294960e5delphij
32394960e5delphij		(*sockaddrout) = (struct sockaddr_storage *) malloc(sizeof(struct sockaddr_in6));
32494960e5delphij		if ((*sockaddrout) == NULL)
32594960e5delphij		{
32619bb0b8hselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
32719bb0b8hselasky			    errno, "malloc() failed");
32894960e5delphij			return -1;
32994960e5delphij		}
33019bb0b8hselasky		sockaddrin_ipv6 = (struct rpcap_sockaddr_in6 *) sockaddrin;
33119bb0b8hselasky		sockaddrout_ipv6 = (struct sockaddr_in6 *) (*sockaddrout);
33219bb0b8hselasky		sockaddrout_ipv6->sin6_family = AF_INET6;
33319bb0b8hselasky		sockaddrout_ipv6->sin6_port = ntohs(sockaddrin_ipv6->port);
33419bb0b8hselasky		sockaddrout_ipv6->sin6_flowinfo = ntohl(sockaddrin_ipv6->flowinfo);
33519bb0b8hselasky		memcpy(&sockaddrout_ipv6->sin6_addr, &sockaddrin_ipv6->addr, sizeof(sockaddrout_ipv6->sin6_addr));
33619bb0b8hselasky		sockaddrout_ipv6->sin6_scope_id = ntohl(sockaddrin_ipv6->scope_id);
33719bb0b8hselasky		break;
33819bb0b8hselasky		}
33919bb0b8hselasky#endif
34094960e5delphij
34119bb0b8hselasky	default:
34219bb0b8hselasky		/*
34319bb0b8hselasky		 * It is neither AF_INET nor AF_INET6 (or, if the OS doesn't
34419bb0b8hselasky		 * support AF_INET6, it's not AF_INET).
34519bb0b8hselasky		 */
34619bb0b8hselasky		*sockaddrout = NULL;
34719bb0b8hselasky		break;
34819bb0b8hselasky	}
34994960e5delphij	return 0;
35094960e5delphij}
35194960e5delphij
35219bb0b8hselasky/*
35319bb0b8hselasky * This function reads a packet from the network socket.  It does not
35419bb0b8hselasky * deliver the packet to a pcap_dispatch()/pcap_loop() callback (hence
35519bb0b8hselasky * the "nocb" string into its name).
35694960e5delphij *
35719bb0b8hselasky * This function is called by pcap_read_rpcap().
35894960e5delphij *
35919bb0b8hselasky * WARNING: By choice, this function does not make use of semaphores. A smarter
36094960e5delphij * implementation should put a semaphore into the data thread, and a signal will
36194960e5delphij * be raised as soon as there is data into the socket buffer.
36294960e5delphij * However this is complicated and it does not bring any advantages when reading
36394960e5delphij * from the network, in which network delays can be much more important than
36494960e5delphij * these optimizations. Therefore, we chose the following approach:
36594960e5delphij * - the 'timeout' chosen by the user is split in two (half on the server side,
36694960e5delphij * with the usual meaning, and half on the client side)
36794960e5delphij * - this function checks for packets; if there are no packets, it waits for
36894960e5delphij * timeout/2 and then it checks again. If packets are still missing, it returns,
36994960e5delphij * otherwise it reads packets.
37094960e5delphij */
37119bb0b8hselaskystatic int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_char **pkt_data)
37294960e5delphij{
37319bb0b8hselasky	struct pcap_rpcap *pr = p->priv;	/* structure used when doing a remote live capture */
37494960e5delphij	struct rpcap_header *header;		/* general header according to the RPCAP format */
37519bb0b8hselasky	struct rpcap_pkthdr *net_pkt_header;	/* header of the packet, from the message */
37619bb0b8hselasky	u_char *net_pkt_data;			/* packet data from the message */
37719bb0b8hselasky	uint32 plen;
37894960e5delphij	int retval;				/* generic return value */
37919bb0b8hselasky	int msglen;
38094960e5delphij
38194960e5delphij	/* Structures needed for the select() call */
38294960e5delphij	struct timeval tv;			/* maximum time the select() can block waiting for data */
38319bb0b8hselasky	fd_set rfds;				/* set of socket descriptors we have to check */
38494960e5delphij
38594960e5delphij	/*
38619bb0b8hselasky	 * Define the packet buffer timeout, to be used in the select()
38794960e5delphij	 * 'timeout', in pcap_t, is in milliseconds; we have to convert it into sec and microsec
38894960e5delphij	 */
38994960e5delphij	tv.tv_sec = p->opt.timeout / 1000;
39094960e5delphij	tv.tv_usec = (p->opt.timeout - tv.tv_sec * 1000) * 1000;
39194960e5delphij
39294960e5delphij	/* Watch out sockdata to see if it has input */
39394960e5delphij	FD_ZERO(&rfds);
39494960e5delphij
39594960e5delphij	/*
39694960e5delphij	 * 'fp->rmt_sockdata' has always to be set before calling the select(),
39794960e5delphij	 * since it is cleared by the select()
39894960e5delphij	 */
39919bb0b8hselasky	FD_SET(pr->rmt_sockdata, &rfds);
40094960e5delphij
40119bb0b8hselasky	retval = select((int) pr->rmt_sockdata + 1, &rfds, NULL, NULL, &tv);
40294960e5delphij	if (retval == -1)
40394960e5delphij	{
40419bb0b8hselasky#ifndef _WIN32
40519bb0b8hselasky		if (errno == EINTR)
40619bb0b8hselasky		{
40719bb0b8hselasky			/* Interrupted. */
40819bb0b8hselasky			return 0;
40919bb0b8hselasky		}
41019bb0b8hselasky#endif
411c2630c9philip		sock_geterror("select()", p->errbuf, PCAP_ERRBUF_SIZE);
41294960e5delphij		return -1;
41394960e5delphij	}
41494960e5delphij
41594960e5delphij	/* There is no data waiting, so return '0' */
41694960e5delphij	if (retval == 0)
41794960e5delphij		return 0;
41894960e5delphij
41994960e5delphij	/*
42094960e5delphij	 * We have to define 'header' as a pointer to a larger buffer,
42194960e5delphij	 * because in case of UDP we have to read all the message within a single call
42294960e5delphij	 */
42319bb0b8hselasky	header = (struct rpcap_header *) p->buffer;
42419bb0b8hselasky	net_pkt_header = (struct rpcap_pkthdr *) ((char *)p->buffer + sizeof(struct rpcap_header));
42519bb0b8hselasky	net_pkt_data = (u_char *)p->buffer + sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr);
42694960e5delphij
42719bb0b8hselasky	if (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)
42894960e5delphij	{
42994960e5delphij		/* Read the entire message from the network */
43019bb0b8hselasky		msglen = sock_recv_dgram(pr->rmt_sockdata, p->buffer,
43119bb0b8hselasky		    p->bufsize, p->errbuf, PCAP_ERRBUF_SIZE);
43219bb0b8hselasky		if (msglen == -1)
43319bb0b8hselasky		{
43419bb0b8hselasky			/* Network error. */
43594960e5delphij			return -1;
43619bb0b8hselasky		}
43719bb0b8hselasky		if (msglen == -3)
43819bb0b8hselasky		{
43919bb0b8hselasky			/* Interrupted receive. */
44019bb0b8hselasky			return 0;
44119bb0b8hselasky		}
44219bb0b8hselasky		if ((size_t)msglen < sizeof(struct rpcap_header))
44319bb0b8hselasky		{
44419bb0b8hselasky			/*
44519bb0b8hselasky			 * Message is shorter than an rpcap header.
44619bb0b8hselasky			 */
44719bb0b8hselasky			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
44819bb0b8hselasky			    "UDP packet message is shorter than an rpcap header");
44919bb0b8hselasky			return -1;
45019bb0b8hselasky		}
45119bb0b8hselasky		plen = ntohl(header->plen);
45219bb0b8hselasky		if ((size_t)msglen < sizeof(struct rpcap_header) + plen)
45319bb0b8hselasky		{
45419bb0b8hselasky			/*
45519bb0b8hselasky			 * Message is shorter than the header claims it
45619bb0b8hselasky			 * is.
45719bb0b8hselasky			 */
45819bb0b8hselasky			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
45919bb0b8hselasky			    "UDP packet message is shorter than its rpcap header claims");
46019bb0b8hselasky			return -1;
46119bb0b8hselasky		}
46294960e5delphij	}
46394960e5delphij	else
46494960e5delphij	{
46519bb0b8hselasky		int status;
46694960e5delphij
46719bb0b8hselasky		if ((size_t)p->cc < sizeof(struct rpcap_header))
46894960e5delphij		{
46919bb0b8hselasky			/*
47019bb0b8hselasky			 * We haven't read any of the packet header yet.
47119bb0b8hselasky			 * The size we should get is the size of the
47219bb0b8hselasky			 * packet header.
47319bb0b8hselasky			 */
47419bb0b8hselasky			status = rpcap_read_packet_msg(pr->rmt_sockdata, p,
47519bb0b8hselasky			    sizeof(struct rpcap_header));
47619bb0b8hselasky			if (status == -1)
47719bb0b8hselasky			{
47819bb0b8hselasky				/* Network error. */
47919bb0b8hselasky				return -1;
48019bb0b8hselasky			}
48119bb0b8hselasky			if (status == -3)
48219bb0b8hselasky			{
48319bb0b8hselasky				/* Interrupted receive. */
48419bb0b8hselasky				return 0;
48519bb0b8hselasky			}
48619bb0b8hselasky		}
48794960e5delphij
48819bb0b8hselasky		/*
48919bb0b8hselasky		 * We have the header, so we know how long the
49019bb0b8hselasky		 * message payload is.  The size we should get
49119bb0b8hselasky		 * is the size of the packet header plus the
49219bb0b8hselasky		 * size of the payload.
49319bb0b8hselasky		 */
49419bb0b8hselasky		plen = ntohl(header->plen);
49519bb0b8hselasky		if (plen > p->bufsize - sizeof(struct rpcap_header))
49619bb0b8hselasky		{
49719bb0b8hselasky			/*
49819bb0b8hselasky			 * This is bigger than the largest
49919bb0b8hselasky			 * record we'd expect.  (We do it by
50019bb0b8hselasky			 * subtracting in order to avoid an
50119bb0b8hselasky			 * overflow.)
50219bb0b8hselasky			 */
50319bb0b8hselasky			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
50419bb0b8hselasky			    "Server sent us a message larger than the largest expected packet message");
50519bb0b8hselasky			return -1;
50619bb0b8hselasky		}
50719bb0b8hselasky		status = rpcap_read_packet_msg(pr->rmt_sockdata, p,
50819bb0b8hselasky		    sizeof(struct rpcap_header) + plen);
50919bb0b8hselasky		if (status == -1)
51019bb0b8hselasky		{
51119bb0b8hselasky			/* Network error. */
51219bb0b8hselasky			return -1;
51394960e5delphij		}
51419bb0b8hselasky		if (status == -3)
51519bb0b8hselasky		{
51619bb0b8hselasky			/* Interrupted receive. */
51719bb0b8hselasky			return 0;
51819bb0b8hselasky		}
51919bb0b8hselasky
52019bb0b8hselasky		/*
52119bb0b8hselasky		 * We have the entire message; reset the buffer pointer
52219bb0b8hselasky		 * and count, as the next read should start a new
52319bb0b8hselasky		 * message.
52419bb0b8hselasky		 */
52519bb0b8hselasky		p->bp = p->buffer;
52619bb0b8hselasky		p->cc = 0;
52794960e5delphij	}
52894960e5delphij
52919bb0b8hselasky	/*
53019bb0b8hselasky	 * We have the entire message.
53119bb0b8hselasky	 */
53219bb0b8hselasky	header->plen = plen;
53319bb0b8hselasky
53419bb0b8hselasky	/*
53519bb0b8hselasky	 * Did the server specify the version we negotiated?
53619bb0b8hselasky	 */
53719bb0b8hselasky	if (rpcap_check_msg_ver(pr->rmt_sockdata, pr->protocol_version,
53819bb0b8hselasky	    header, p->errbuf) == -1)
53994960e5delphij	{
54019bb0b8hselasky		return 0;	/* Return 'no packets received' */
54194960e5delphij	}
54294960e5delphij
54319bb0b8hselasky	/*
54419bb0b8hselasky	 * Is this a RPCAP_MSG_PACKET message?
54519bb0b8hselasky	 */
54619bb0b8hselasky	if (header->type != RPCAP_MSG_PACKET)
54794960e5delphij	{
54819bb0b8hselasky		return 0;	/* Return 'no packets received' */
54919bb0b8hselasky	}
55094960e5delphij
55119bb0b8hselasky	if (ntohl(net_pkt_header->caplen) > plen)
55219bb0b8hselasky	{
55319bb0b8hselasky		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
55419bb0b8hselasky		    "Packet's captured data goes past the end of the received packet message.");
55519bb0b8hselasky		return -1;
55619bb0b8hselasky	}
55794960e5delphij
55819bb0b8hselasky	/* Fill in packet header */
55919bb0b8hselasky	pkt_header->caplen = ntohl(net_pkt_header->caplen);
56019bb0b8hselasky	pkt_header->len = ntohl(net_pkt_header->len);
56119bb0b8hselasky	pkt_header->ts.tv_sec = ntohl(net_pkt_header->timestamp_sec);
56219bb0b8hselasky	pkt_header->ts.tv_usec = ntohl(net_pkt_header->timestamp_usec);
56394960e5delphij
56419bb0b8hselasky	/* Supply a pointer to the beginning of the packet data */
56519bb0b8hselasky	*pkt_data = net_pkt_data;
56694960e5delphij
56719bb0b8hselasky	/*
56819bb0b8hselasky	 * I don't update the counter of the packets dropped by the network since we're using TCP,
56919bb0b8hselasky	 * therefore no packets are dropped. Just update the number of packets received correctly
57019bb0b8hselasky	 */
57119bb0b8hselasky	pr->TotCapt++;
57294960e5delphij
57319bb0b8hselasky	if (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)
57419bb0b8hselasky	{
57519bb0b8hselasky		unsigned int npkt;
57694960e5delphij
57719bb0b8hselasky		/* We're using UDP, so we need to update the counter of the packets dropped by the network */
57819bb0b8hselasky		npkt = ntohl(net_pkt_header->npkt);
57994960e5delphij
58019bb0b8hselasky		if (pr->TotCapt != npkt)
58194960e5delphij		{
58219bb0b8hselasky			pr->TotNetDrops += (npkt - pr->TotCapt);
58319bb0b8hselasky			pr->TotCapt = npkt;
58494960e5delphij		}
58594960e5delphij	}
58694960e5delphij
58719bb0b8hselasky	/* Packet read successfully */
58819bb0b8hselasky	return 1;
58994960e5delphij}
59094960e5delphij
59119bb0b8hselasky/*
59219bb0b8hselasky * This function reads a packet from the network socket.
59394960e5delphij *
59494960e5delphij * This function relies on the pcap_read_nocb_remote to deliver packets. The
59594960e5delphij * difference, here, is that as soon as a packet is read, it is delivered
59694960e5delphij * to the application by means of a callback function.
59794960e5delphij */
59819bb0b8hselaskystatic int pcap_read_rpcap(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
59994960e5delphij{
60019bb0b8hselasky	struct pcap_rpcap *pr = p->priv;	/* structure used when doing a remote live capture */
60119bb0b8hselasky	struct pcap_pkthdr pkt_header;
60294960e5delphij	u_char *pkt_data;
60394960e5delphij	int n = 0;
60419bb0b8hselasky	int ret;
60519bb0b8hselasky
60619bb0b8hselasky	/*
60719bb0b8hselasky	 * If this is client-side, and we haven't already started
60819bb0b8hselasky	 * the capture, start it now.
60919bb0b8hselasky	 */
61019bb0b8hselasky	if (pr->rmt_clientside)
61119bb0b8hselasky	{
61219bb0b8hselasky		/* We are on an remote capture */
61319bb0b8hselasky		if (!pr->rmt_capstarted)
61419bb0b8hselasky		{
61519bb0b8hselasky			/*
61619bb0b8hselasky			 * The capture isn't started yet, so try to
61719bb0b8hselasky			 * start it.
61819bb0b8hselasky			 */
61919bb0b8hselasky			if (pcap_startcapture_remote(p))
62019bb0b8hselasky				return -1;
62119bb0b8hselasky		}
62219bb0b8hselasky	}
62394960e5delphij
62419bb0b8hselasky	while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt))
62594960e5delphij	{
62619bb0b8hselasky		/*
62719bb0b8hselasky		 * Has "pcap_breakloop()" been called?
62819bb0b8hselasky		 */
62919bb0b8hselasky		if (p->break_loop) {
63019bb0b8hselasky			/*
63119bb0b8hselasky			 * Yes - clear the flag that indicates that it
63219bb0b8hselasky			 * has, and return PCAP_ERROR_BREAK to indicate
63319bb0b8hselasky			 * that we were told to break out of the loop.
63419bb0b8hselasky			 */
63519bb0b8hselasky			p->break_loop = 0;
63619bb0b8hselasky			return (PCAP_ERROR_BREAK);
63719bb0b8hselasky		}
63819bb0b8hselasky
63919bb0b8hselasky		/*
64019bb0b8hselasky		 * Read some packets.
64119bb0b8hselasky		 */
64219bb0b8hselasky		ret = pcap_read_nocb_remote(p, &pkt_header, &pkt_data);
64319bb0b8hselasky		if (ret == 1)
64494960e5delphij		{
64519bb0b8hselasky			/*
64619bb0b8hselasky			 * We got a packet.  Hand it to the callback
64719bb0b8hselasky			 * and count it so we can return the count.
64819bb0b8hselasky			 */
64919bb0b8hselasky			(*callback)(user, &pkt_header, pkt_data);
65094960e5delphij			n++;
65194960e5delphij		}
65219bb0b8hselasky		else if (ret == -1)
65319bb0b8hselasky		{
65419bb0b8hselasky			/* Error. */
65519bb0b8hselasky			return ret;
65619bb0b8hselasky		}
65794960e5delphij		else
65819bb0b8hselasky		{
65919bb0b8hselasky			/*
66019bb0b8hselasky			 * No packet; this could mean that we timed
66119bb0b8hselasky			 * out, or that we got interrupted, or that
66219bb0b8hselasky			 * we got a bad packet.
66319bb0b8hselasky			 *
66419bb0b8hselasky			 * Were we told to break out of the loop?
66519bb0b8hselasky			 */
66619bb0b8hselasky			if (p->break_loop) {
66719bb0b8hselasky				/*
66819bb0b8hselasky				 * Yes.
66919bb0b8hselasky				 */
67019bb0b8hselasky				p->break_loop = 0;
67119bb0b8hselasky				return (PCAP_ERROR_BREAK);
67219bb0b8hselasky			}
67319bb0b8hselasky			/* No - return the number of packets we've processed. */
67494960e5delphij			return n;
67519bb0b8hselasky		}
67694960e5delphij	}
67794960e5delphij	return n;
67894960e5delphij}
67994960e5delphij
68019bb0b8hselasky/*
68119bb0b8hselasky * This function sends a CLOSE command to the capture server.
68294960e5delphij *
68319bb0b8hselasky * It is called when the user calls pcap_close().  It sends a command
68419bb0b8hselasky * to our peer that says 'ok, let's stop capturing'.
68594960e5delphij *
68619bb0b8hselasky * WARNING: Since we're closing the connection, we do not check for errors.
68794960e5delphij */
68819bb0b8hselaskystatic void pcap_cleanup_rpcap(pcap_t *fp)
68994960e5delphij{
69019bb0b8hselasky	struct pcap_rpcap *pr = fp->priv;	/* structure used when doing a remote live capture */
69194960e5delphij	struct rpcap_header header;		/* header of the RPCAP packet */
69294960e5delphij	struct activehosts *temp;		/* temp var needed to scan the host list chain, to detect if we're in active mode */
69319bb0b8hselasky	int active = 0;				/* active mode or not? */
69494960e5delphij
69594960e5delphij	/* detect if we're in active mode */
69694960e5delphij	temp = activeHosts;
69794960e5delphij	while (temp)
69894960e5delphij	{
69919bb0b8hselasky		if (temp->sockctrl == pr->rmt_sockctrl)
70094960e5delphij		{
70194960e5delphij			active = 1;
70294960e5delphij			break;
70394960e5delphij		}
70494960e5delphij		temp = temp->next;
70594960e5delphij	}
70694960e5delphij
70794960e5delphij	if (!active)
70894960e5delphij	{
70919bb0b8hselasky		rpcap_createhdr(&header, pr->protocol_version,
71019bb0b8hselasky		    RPCAP_MSG_CLOSE, 0, 0);
71194960e5delphij
71219bb0b8hselasky		/*
71319bb0b8hselasky		 * Send the close request; don't report any errors, as
71419bb0b8hselasky		 * we're closing this pcap_t, and have no place to report
71519bb0b8hselasky		 * the error.  No reply is sent to this message.
71619bb0b8hselasky		 */
71719bb0b8hselasky		(void)sock_send(pr->rmt_sockctrl, (char *)&header,
71819bb0b8hselasky		    sizeof(struct rpcap_header), NULL, 0);
71994960e5delphij	}
72094960e5delphij	else
72194960e5delphij	{
72219bb0b8hselasky		rpcap_createhdr(&header, pr->protocol_version,
72319bb0b8hselasky		    RPCAP_MSG_ENDCAP_REQ, 0, 0);
72494960e5delphij
72519bb0b8hselasky		/*
72619bb0b8hselasky		 * Send the end capture request; don't report any errors,
72719bb0b8hselasky		 * as we're closing this pcap_t, and have no place to
72819bb0b8hselasky		 * report the error.
72919bb0b8hselasky		 */
73019bb0b8hselasky		if (sock_send(pr->rmt_sockctrl, (char *)&header,
73119bb0b8hselasky		    sizeof(struct rpcap_header), NULL, 0) == 0)
73219bb0b8hselasky		{
73319bb0b8hselasky			/*
73419bb0b8hselasky			 * Wait for the answer; don't report any errors,
73519bb0b8hselasky			 * as we're closing this pcap_t, and have no
73619bb0b8hselasky			 * place to report the error.
73719bb0b8hselasky			 */
73819bb0b8hselasky			if (rpcap_process_msg_header(pr->rmt_sockctrl,
73919bb0b8hselasky			    pr->protocol_version, RPCAP_MSG_ENDCAP_REQ,
74019bb0b8hselasky			    &header, NULL) == 0)
74119bb0b8hselasky			{
74219bb0b8hselasky				(void)rpcap_discard(pr->rmt_sockctrl,
74319bb0b8hselasky				    header.plen, NULL);
74419bb0b8hselasky			}
74519bb0b8hselasky		}
74694960e5delphij	}
74794960e5delphij
74819bb0b8hselasky	if (pr->rmt_sockdata)
74994960e5delphij	{
75019bb0b8hselasky		sock_close(pr->rmt_sockdata, NULL, 0);
75119bb0b8hselasky		pr->rmt_sockdata = 0;
75294960e5delphij	}
75394960e5delphij
75419bb0b8hselasky	if ((!active) && (pr->rmt_sockctrl))
75519bb0b8hselasky		sock_close(pr->rmt_sockctrl, NULL, 0);
75694960e5delphij
75719bb0b8hselasky	pr->rmt_sockctrl = 0;
75894960e5delphij
75919bb0b8hselasky	if (pr->currentfilter)
76094960e5delphij	{
76119bb0b8hselasky		free(pr->currentfilter);
76219bb0b8hselasky		pr->currentfilter = NULL;
76394960e5delphij	}
76494960e5delphij
765c2630c9philip	pcap_cleanup_live_common(fp);
766c2630c9philip
76794960e5delphij	/* To avoid inconsistencies in the number of sock_init() */
76894960e5delphij	sock_cleanup();
76994960e5delphij}
77094960e5delphij
77119bb0b8hselasky/*
77219bb0b8hselasky * This function retrieves network statistics from our peer;
77319bb0b8hselasky * it provides only the standard statistics.
77494960e5delphij */
77519bb0b8hselaskystatic int pcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps)
77694960e5delphij{
77794960e5delphij	struct pcap_stat *retval;
77894960e5delphij
77919bb0b8hselasky	retval = rpcap_stats_rpcap(p, ps, PCAP_STATS_STANDARD);
78094960e5delphij
78194960e5delphij	if (retval)
78294960e5delphij		return 0;
78394960e5delphij	else
78494960e5delphij		return -1;
78594960e5delphij}
78694960e5delphij
78794960e5delphij#ifdef _WIN32
78819bb0b8hselasky/*
78919bb0b8hselasky * This function retrieves network statistics from our peer;
79019bb0b8hselasky * it provides the additional statistics supported by pcap_stats_ex().
79194960e5delphij */
79219bb0b8hselaskystatic struct pcap_stat *pcap_stats_ex_rpcap(pcap_t *p, int *pcap_stat_size)
79394960e5delphij{
79494960e5delphij	*pcap_stat_size = sizeof (p->stat);
79594960e5delphij
79694960e5delphij	/* PCAP_STATS_EX (third param) means 'extended pcap_stats()' */
79719bb0b8hselasky	return (rpcap_stats_rpcap(p, &(p->stat), PCAP_STATS_EX));
79894960e5delphij}
79994960e5delphij#endif
80094960e5delphij
80119bb0b8hselasky/*
80219bb0b8hselasky * This function retrieves network statistics from our peer.  It
80319bb0b8hselasky * is used by the two previous functions.
80419bb0b8hselasky *
80519bb0b8hselasky * It can be called in two modes:
80619bb0b8hselasky * - PCAP_STATS_STANDARD: if we want just standard statistics (i.e.,
80719bb0b8hselasky *   for pcap_stats())
80819bb0b8hselasky * - PCAP_STATS_EX: if we want extended statistics (i.e., for
80919bb0b8hselasky *   pcap_stats_ex())
81019bb0b8hselasky *
81119bb0b8hselasky * This 'mode' parameter is needed because in pcap_stats() the variable that
81219bb0b8hselasky * keeps the statistics is allocated by the user. On Windows, this structure
81319bb0b8hselasky * has been extended in order to keep new stats. However, if the user has a
81419bb0b8hselasky * smaller structure and it passes it to pcap_stats(), this function will
81519bb0b8hselasky * try to fill in more data than the size of the structure, so that memory
81619bb0b8hselasky * after the structure will be overwritten.
81719bb0b8hselasky *
81819bb0b8hselasky * So, we need to know it we have to copy just the standard fields, or the
81919bb0b8hselasky * extended fields as well.
82019bb0b8hselasky *
82119bb0b8hselasky * In case we want to copy the extended fields as well, the problem of
82219bb0b8hselasky * memory overflow no longer exists because the structure that's filled
82319bb0b8hselasky * in is part of the pcap_t, so that it can be guaranteed to be large
82419bb0b8hselasky * enough for the additional statistics.
82594960e5delphij *
82694960e5delphij * \param p: the pcap_t structure related to the current instance.
82794960e5delphij *
82819bb0b8hselasky * \param ps: a pointer to a 'pcap_stat' structure, needed for compatibility
82919bb0b8hselasky * with pcap_stat(), where the structure is allocated by the user. In case
83019bb0b8hselasky * of pcap_stats_ex(), this structure and the function return value point
83119bb0b8hselasky * to the same variable.
83294960e5delphij *
83394960e5delphij * \param mode: one of PCAP_STATS_STANDARD or PCAP_STATS_EX.
83494960e5delphij *
83594960e5delphij * \return The structure that keeps the statistics, or NULL in case of error.
83694960e5delphij * The error string is placed in the pcap_t structure.
83794960e5delphij */
83819bb0b8hselaskystatic struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int mode)
83994960e5delphij{
84019bb0b8hselasky	struct pcap_rpcap *pr = p->priv;	/* structure used when doing a remote live capture */
84194960e5delphij	struct rpcap_header header;		/* header of the RPCAP packet */
84294960e5delphij	struct rpcap_stats netstats;		/* statistics sent on the network */
84319bb0b8hselasky	uint32 plen;				/* data remaining in the message */
84494960e5delphij
84519bb0b8hselasky#ifdef _WIN32
84619bb0b8hselasky	if (mode != PCAP_STATS_STANDARD && mode != PCAP_STATS_EX)
84719bb0b8hselasky#else
84819bb0b8hselasky	if (mode != PCAP_STATS_STANDARD)
84919bb0b8hselasky#endif
85019bb0b8hselasky	{
85119bb0b8hselasky		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
85219bb0b8hselasky		    "Invalid stats mode %d", mode);
85319bb0b8hselasky		return NULL;
85419bb0b8hselasky	}
85594960e5delphij
85694960e5delphij	/*
85719bb0b8hselasky	 * If the capture has not yet started, we cannot request statistics
85819bb0b8hselasky	 * for the capture from our peer, so we return 0 for all statistics,
85919bb0b8hselasky	 * as nothing's been seen yet.
86094960e5delphij	 */
86119bb0b8hselasky	if (!pr->rmt_capstarted)
86294960e5delphij	{
86319bb0b8hselasky		ps->ps_drop = 0;
86419bb0b8hselasky		ps->ps_ifdrop = 0;
86519bb0b8hselasky		ps->ps_recv = 0;
86619bb0b8hselasky#ifdef _WIN32
86719bb0b8hselasky		if (mode == PCAP_STATS_EX)
86894960e5delphij		{
86994960e5delphij			ps->ps_capt = 0;
87094960e5delphij			ps->ps_sent = 0;
87119bb0b8hselasky			ps->ps_netdrop = 0;
87294960e5delphij		}
87319bb0b8hselasky#endif /* _WIN32 */
87494960e5delphij
87594960e5delphij		return ps;
87694960e5delphij	}
87794960e5delphij
87819bb0b8hselasky	rpcap_createhdr(&header, pr->protocol_version,
87919bb0b8hselasky	    RPCAP_MSG_STATS_REQ, 0, 0);
88094960e5delphij
88194960e5delphij	/* Send the PCAP_STATS command */
88219bb0b8hselasky	if (sock_send(pr->rmt_sockctrl, (char *)&header,
88319bb0b8hselasky	    sizeof(struct rpcap_header), p->errbuf, PCAP_ERRBUF_SIZE) < 0)
88419bb0b8hselasky		return NULL;		/* Unrecoverable network error */
88594960e5delphij
88619bb0b8hselasky	/* Receive and process the reply message header. */
88719bb0b8hselasky	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
88819bb0b8hselasky	    RPCAP_MSG_STATS_REQ, &header, p->errbuf) == -1)
88919bb0b8hselasky		return NULL;		/* Error */
89094960e5delphij
89119bb0b8hselasky	plen = header.plen;
89294960e5delphij
89319bb0b8hselasky	/* Read the reply body */
89419bb0b8hselasky	if (rpcap_recv(pr->rmt_sockctrl, (char *)&netstats,
89519bb0b8hselasky	    sizeof(struct rpcap_stats), &plen, p->errbuf) == -1)
89694960e5delphij		goto error;
89794960e5delphij
89819bb0b8hselasky	ps->ps_drop = ntohl(netstats.krnldrop);
89919bb0b8hselasky	ps->ps_ifdrop = ntohl(netstats.ifdrop);
90019bb0b8hselasky	ps->ps_recv = ntohl(netstats.ifrecv);
90119bb0b8hselasky#ifdef _WIN32
90219bb0b8hselasky	if (mode == PCAP_STATS_EX)
90394960e5delphij	{
90419bb0b8hselasky		ps->ps_capt = pr->TotCapt;
90519bb0b8hselasky		ps->ps_netdrop = pr->TotNetDrops;
90694960e5delphij		ps->ps_sent = ntohl(netstats.svrcapt);
90794960e5delphij	}
90819bb0b8hselasky#endif /* _WIN32 */
90994960e5delphij
91019bb0b8hselasky	/* Discard the rest of the message. */
91119bb0b8hselasky	if (rpcap_discard(pr->rmt_sockctrl, plen, p->errbuf) == -1)
912c2630c9philip		goto error_nodiscard;
91394960e5delphij
91494960e5delphij	return ps;
91594960e5delphij
91694960e5delphijerror:
91719bb0b8hselasky	/*
91819bb0b8hselasky	 * Discard the rest of the message.
91919bb0b8hselasky	 * We already reported an error; if this gets an error, just
92019bb0b8hselasky	 * drive on.
92119bb0b8hselasky	 */
92219bb0b8hselasky	(void)rpcap_discard(pr->rmt_sockctrl, plen, NULL);
92394960e5delphij
924c2630c9philiperror_nodiscard:
92594960e5delphij	return NULL;
92694960e5delphij}
92794960e5delphij
92819bb0b8hselasky/*
92919bb0b8hselasky * This function returns the entry in the list of active hosts for this
93019bb0b8hselasky * active connection (active mode only), or NULL if there is no
93119bb0b8hselasky * active connection or an error occurred.  It is just for internal
93219bb0b8hselasky * use.
93394960e5delphij *
93419bb0b8hselasky * \param host: a string that keeps the host name of the host for which we
93519bb0b8hselasky * want to get the socket ID for that active connection.
93694960e5delphij *
93719bb0b8hselasky * \param error: a pointer to an int that is set to 1 if an error occurred
93819bb0b8hselasky * and 0 otherwise.
93994960e5delphij *
94019bb0b8hselasky * \param errbuf: a pointer to a user-allocated buffer (of size
94119bb0b8hselasky * PCAP_ERRBUF_SIZE) that will contain the error message (in case
94219bb0b8hselasky * there is one).
94394960e5delphij *
94419bb0b8hselasky * \return the entry for this host in the list of active connections
94519bb0b8hselasky * if found, NULL if it's not found or there's an error.
94694960e5delphij */
94719bb0b8hselaskystatic struct activehosts *
94819bb0b8hselaskyrpcap_remoteact_getsock(const char *host, int *error, char *errbuf)
94994960e5delphij{
95019bb0b8hselasky	struct activehosts *temp;			/* temp var needed to scan the host list chain */
95119bb0b8hselasky	struct addrinfo hints, *addrinfo, *ai_next;	/* temp var needed to translate between hostname to its address */
95219bb0b8hselasky	int retval;
95394960e5delphij
95419bb0b8hselasky	/* retrieve the network address corresponding to 'host' */
95594960e5delphij	addrinfo = NULL;
95619bb0b8hselasky	memset(&hints, 0, sizeof(struct addrinfo));
95719bb0b8hselasky	hints.ai_family = PF_UNSPEC;
95819bb0b8hselasky	hints.ai_socktype = SOCK_STREAM;
95994960e5delphij
96019bb0b8hselasky	retval = getaddrinfo(host, "0", &hints, &addrinfo);
96119bb0b8hselasky	if (retval != 0)
96294960e5delphij	{
96319bb0b8hselasky		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s",
96419bb0b8hselasky		    gai_strerror(retval));
96519bb0b8hselasky		*error = 1;
96619bb0b8hselasky		return NULL;
96794960e5delphij	}
96894960e5delphij
96919bb0b8hselasky	temp = activeHosts;
97094960e5delphij
97119bb0b8hselasky	while (temp)
97294960e5delphij	{
97319bb0b8hselasky		ai_next = addrinfo;
97419bb0b8hselasky		while (ai_next)
97594960e5delphij		{
97619bb0b8hselasky			if (sock_cmpaddr(&temp->host, (struct sockaddr_storage *) ai_next->ai_addr) == 0)
97719bb0b8hselasky			{
97819bb0b8hselasky				*error = 0;
97919bb0b8hselasky				freeaddrinfo(addrinfo);
98019bb0b8hselasky				return temp;
98119bb0b8hselasky			}
98294960e5delphij
98319bb0b8hselasky			ai_next = ai_next->ai_next;
98494960e5delphij		}
98519bb0b8hselasky		temp = temp->next;
98694960e5delphij	}
98794960e5delphij
98894960e5delphij	if (addrinfo)
98994960e5delphij		freeaddrinfo(addrinfo);
99094960e5delphij
99119bb0b8hselasky	/*
99219bb0b8hselasky	 * The host for which you want to get the socket ID does not have an
99319bb0b8hselasky	 * active connection.
99419bb0b8hselasky	 */
99519bb0b8hselasky	*error = 0;
99619bb0b8hselasky	return NULL;
99794960e5delphij}
99894960e5delphij
99919bb0b8hselasky/*
100019bb0b8hselasky * This function starts a remote capture.
100194960e5delphij *
100219bb0b8hselasky * This function is required since the RPCAP protocol decouples the 'open'
100319bb0b8hselasky * from the 'start capture' functions.
100419bb0b8hselasky * This function takes all the parameters needed (which have been stored
100519bb0b8hselasky * into the pcap_t structure) and sends them to the server.
100694960e5delphij *
100794960e5delphij * \param fp: the pcap_t descriptor of the device currently open.
100894960e5delphij *
100919bb0b8hselasky * \return '0' if everything is fine, '-1' otherwise. The error message
101019bb0b8hselasky * (if one) is returned into the 'errbuf' field of the pcap_t structure.
101194960e5delphij */
101219bb0b8hselaskystatic int pcap_startcapture_remote(pcap_t *fp)
101394960e5delphij{
101419bb0b8hselasky	struct pcap_rpcap *pr = fp->priv;	/* structure used when doing a remote live capture */
101594960e5delphij	char sendbuf[RPCAP_NETBUF_SIZE];	/* temporary buffer in which data to be sent is buffered */
101694960e5delphij	int sendbufidx = 0;			/* index which keeps the number of bytes currently buffered */
101719bb0b8hselasky	char portdata[PCAP_BUF_SIZE];		/* temp variable needed to keep the network port for the data connection */
101819bb0b8hselasky	uint32 plen;
101994960e5delphij	int active = 0;				/* '1' if we're in active mode */
102094960e5delphij	struct activehosts *temp;		/* temp var needed to scan the host list chain, to detect if we're in active mode */
102194960e5delphij	char host[INET6_ADDRSTRLEN + 1];	/* numeric name of the other host */
102294960e5delphij
102394960e5delphij	/* socket-related variables*/
102494960e5delphij	struct addrinfo hints;			/* temp, needed to open a socket connection */
102594960e5delphij	struct addrinfo *addrinfo;		/* temp, needed to open a socket connection */
102694960e5delphij	SOCKET sockdata = 0;			/* socket descriptor of the data connection */
102794960e5delphij	struct sockaddr_storage saddr;		/* temp, needed to retrieve the network data port chosen on the local machine */
102894960e5delphij	socklen_t saddrlen;			/* temp, needed to retrieve the network data port chosen on the local machine */
102994960e5delphij	int ai_family;				/* temp, keeps the address family used by the control connection */
103094960e5delphij
103194960e5delphij	/* RPCAP-related variables*/
103294960e5delphij	struct rpcap_header header;			/* header of the RPCAP packet */
103394960e5delphij	struct rpcap_startcapreq *startcapreq;		/* start capture request message */
103494960e5delphij	struct rpcap_startcapreply startcapreply;	/* start capture reply message */
103594960e5delphij
103694960e5delphij	/* Variables related to the buffer setting */
103719bb0b8hselasky	int res;
103819bb0b8hselasky	socklen_t itemp;
103994960e5delphij	int sockbufsize = 0;
104019bb0b8hselasky	uint32 server_sockbufsize;
104194960e5delphij
104294960e5delphij	/*
104394960e5delphij	 * Let's check if sampling has been required.
104494960e5delphij	 * If so, let's set it first
104594960e5delphij	 */
104694960e5delphij	if (pcap_setsampling_remote(fp) != 0)
104794960e5delphij		return -1;
104894960e5delphij
104994960e5delphij	/* detect if we're in active mode */
105094960e5delphij	temp = activeHosts;
105194960e5delphij	while (temp)
105294960e5delphij	{
105319bb0b8hselasky		if (temp->sockctrl == pr->rmt_sockctrl)
105494960e5delphij		{
105594960e5delphij			active = 1;
105694960e5delphij			break;
105794960e5delphij		}
105894960e5delphij		temp = temp->next;
105994960e5delphij	}
106094960e5delphij
106194960e5delphij	addrinfo = NULL;
106294960e5delphij
106394960e5delphij	/*
106494960e5delphij	 * Gets the complete sockaddr structure used in the ctrl connection
106594960e5delphij	 * This is needed to get the address family of the control socket
106694960e5delphij	 * Tip: I cannot save the ai_family of the ctrl sock in the pcap_t struct,
106794960e5delphij	 * since the ctrl socket can already be open in case of active mode;
106894960e5delphij	 * so I would have to call getpeername() anyway
106994960e5delphij	 */
107094960e5delphij	saddrlen = sizeof(struct sockaddr_storage);
107119bb0b8hselasky	if (getpeername(pr->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1)
107294960e5delphij	{
1073c2630c9philip		sock_geterror("getsockname()", fp->errbuf, PCAP_ERRBUF_SIZE);
107419bb0b8hselasky		goto error_nodiscard;
107594960e5delphij	}
107694960e5delphij	ai_family = ((struct sockaddr_storage *) &saddr)->ss_family;
107794960e5delphij
107894960e5delphij	/* Get the numeric address of the remote host we are connected to */
107994960e5delphij	if (getnameinfo((struct sockaddr *) &saddr, saddrlen, host,
108094960e5delphij		sizeof(host), NULL, 0, NI_NUMERICHOST))
108194960e5delphij	{
1082c2630c9philip		sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE);
108319bb0b8hselasky		goto error_nodiscard;
108494960e5delphij	}
108594960e5delphij
108694960e5delphij	/*
108794960e5delphij	 * Data connection is opened by the server toward the client if:
108894960e5delphij	 * - we're using TCP, and the user wants us to be in active mode
108994960e5delphij	 * - we're using UDP
109094960e5delphij	 */
109119bb0b8hselasky	if ((active) || (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP))
109294960e5delphij	{
109394960e5delphij		/*
109494960e5delphij		 * We have to create a new socket to receive packets
109594960e5delphij		 * We have to do that immediately, since we have to tell the other
109694960e5delphij		 * end which network port we picked up
109794960e5delphij		 */
109894960e5delphij		memset(&hints, 0, sizeof(struct addrinfo));
109994960e5delphij		/* TEMP addrinfo is NULL in case of active */
110094960e5delphij		hints.ai_family = ai_family;	/* Use the same address family of the control socket */
110119bb0b8hselasky		hints.ai_socktype = (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM;
110294960e5delphij		hints.ai_flags = AI_PASSIVE;	/* Data connection is opened by the server toward the client */
110394960e5delphij
110494960e5delphij		/* Let's the server pick up a free network port for us */
110594960e5delphij		if (sock_initaddress(NULL, "0", &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
110619bb0b8hselasky			goto error_nodiscard;
110794960e5delphij
110894960e5delphij		if ((sockdata = sock_open(addrinfo, SOCKOPEN_SERVER,
110994960e5delphij			1 /* max 1 connection in queue */, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
111019bb0b8hselasky			goto error_nodiscard;
111194960e5delphij
111294960e5delphij		/* addrinfo is no longer used */
111394960e5delphij		freeaddrinfo(addrinfo);
111494960e5delphij		addrinfo = NULL;
111594960e5delphij
111694960e5delphij		/* get the complete sockaddr structure used in the data connection */
111794960e5delphij		saddrlen = sizeof(struct sockaddr_storage);
111894960e5delphij		if (getsockname(sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1)
111994960e5delphij		{
1120c2630c9philip			sock_geterror("getsockname()", fp->errbuf, PCAP_ERRBUF_SIZE);
112119bb0b8hselasky			goto error_nodiscard;
112294960e5delphij		}
112394960e5delphij
112494960e5delphij		/* Get the local port the system picked up */
112594960e5delphij		if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL,
112694960e5delphij			0, portdata, sizeof(portdata), NI_NUMERICSERV))
112794960e5delphij		{
1128c2630c9philip			sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE);
112919bb0b8hselasky			goto error_nodiscard;
113094960e5delphij		}
113194960e5delphij	}
113294960e5delphij
113394960e5delphij	/*
113494960e5delphij	 * Now it's time to start playing with the RPCAP protocol
113594960e5delphij	 * RPCAP start capture command: create the request message
113694960e5delphij	 */
113794960e5delphij	if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
113894960e5delphij		&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE))
113919bb0b8hselasky		goto error_nodiscard;
114094960e5delphij
114119bb0b8hselasky	rpcap_createhdr((struct rpcap_header *) sendbuf,
114219bb0b8hselasky	    pr->protocol_version, RPCAP_MSG_STARTCAP_REQ, 0,
114319bb0b8hselasky	    sizeof(struct rpcap_startcapreq) + sizeof(struct rpcap_filter) + fp->fcode.bf_len * sizeof(struct rpcap_filterbpf_insn));
114494960e5delphij
114594960e5delphij	/* Fill the structure needed to open an adapter remotely */
114694960e5delphij	startcapreq = (struct rpcap_startcapreq *) &sendbuf[sendbufidx];
114794960e5delphij
114894960e5delphij	if (sock_bufferize(NULL, sizeof(struct rpcap_startcapreq), NULL,
114994960e5delphij		&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE))
115019bb0b8hselasky		goto error_nodiscard;
115194960e5delphij
115294960e5delphij	memset(startcapreq, 0, sizeof(struct rpcap_startcapreq));
115394960e5delphij
115494960e5delphij	/* By default, apply half the timeout on one side, half of the other */
115594960e5delphij	fp->opt.timeout = fp->opt.timeout / 2;
115694960e5delphij	startcapreq->read_timeout = htonl(fp->opt.timeout);
115794960e5delphij
115894960e5delphij	/* portdata on the openreq is meaningful only if we're in active mode */
115919bb0b8hselasky	if ((active) || (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP))
116094960e5delphij	{
116194960e5delphij		sscanf(portdata, "%d", (int *)&(startcapreq->portdata));	/* cast to avoid a compiler warning */
116294960e5delphij		startcapreq->portdata = htons(startcapreq->portdata);
116394960e5delphij	}
116494960e5delphij
116594960e5delphij	startcapreq->snaplen = htonl(fp->snapshot);
116694960e5delphij	startcapreq->flags = 0;
116794960e5delphij
116819bb0b8hselasky	if (pr->rmt_flags & PCAP_OPENFLAG_PROMISCUOUS)
116994960e5delphij		startcapreq->flags |= RPCAP_STARTCAPREQ_FLAG_PROMISC;
117019bb0b8hselasky	if (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)
117194960e5delphij		startcapreq->flags |= RPCAP_STARTCAPREQ_FLAG_DGRAM;
117294960e5delphij	if (active)
117394960e5delphij		startcapreq->flags |= RPCAP_STARTCAPREQ_FLAG_SERVEROPEN;
117494960e5delphij
117594960e5delphij	startcapreq->flags = htons(startcapreq->flags);
117694960e5delphij
117794960e5delphij	/* Pack the capture filter */
117894960e5delphij	if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, &fp->fcode))
117919bb0b8hselasky		goto error_nodiscard;
118094960e5delphij
118119bb0b8hselasky	if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
118219bb0b8hselasky	    PCAP_ERRBUF_SIZE) < 0)
118319bb0b8hselasky		goto error_nodiscard;
118494960e5delphij
118519bb0b8hselasky	/* Receive and process the reply message header. */
118619bb0b8hselasky	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
118719bb0b8hselasky	    RPCAP_MSG_STARTCAP_REQ, &header, fp->errbuf) == -1)
118819bb0b8hselasky		goto error_nodiscard;
118994960e5delphij
119019bb0b8hselasky	plen = header.plen;
119194960e5delphij
119219bb0b8hselasky	if (rpcap_recv(pr->rmt_sockctrl, (char *)&startcapreply,
119319bb0b8hselasky	    sizeof(struct rpcap_startcapreply), &plen, fp->errbuf) == -1)
119494960e5delphij		goto error;
119594960e5delphij
119694960e5delphij	/*
119794960e5delphij	 * In case of UDP data stream, the connection is always opened by the daemon
119894960e5delphij	 * So, this case is already covered by the code above.
119994960e5delphij	 * Now, we have still to handle TCP connections, because:
120094960e5delphij	 * - if we're in active mode, we have to wait for a remote connection
120194960e5delphij	 * - if we're in passive more, we have to start a connection
120294960e5delphij	 *
120394960e5delphij	 * We have to do he job in two steps because in case we're opening a TCP connection, we have
120494960e5delphij	 * to tell the port we're using to the remote side; in case we're accepting a TCP
120594960e5delphij	 * connection, we have to wait this info from the remote side.
120694960e5delphij	 */
120719bb0b8hselasky	if (!(pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP))
120894960e5delphij	{
120994960e5delphij		if (!active)
121094960e5delphij		{
121194960e5delphij			memset(&hints, 0, sizeof(struct addrinfo));
121294960e5delphij			hints.ai_family = ai_family;		/* Use the same address family of the control socket */
121319bb0b8hselasky			hints.ai_socktype = (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM;
121494960e5delphij			pcap_snprintf(portdata, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata));
121594960e5delphij
121694960e5delphij			/* Let's the server pick up a free network port for us */
121794960e5delphij			if (sock_initaddress(host, portdata, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1)
121894960e5delphij				goto error;
121994960e5delphij
122094960e5delphij			if ((sockdata = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
122194960e5delphij				goto error;
122294960e5delphij
122394960e5delphij			/* addrinfo is no longer used */
122494960e5delphij			freeaddrinfo(addrinfo);
122594960e5delphij			addrinfo = NULL;
122694960e5delphij		}
122794960e5delphij		else
122894960e5delphij		{
122994960e5delphij			SOCKET socktemp;	/* We need another socket, since we're going to accept() a connection */
123094960e5delphij
123194960e5delphij			/* Connection creation */
123294960e5delphij			saddrlen = sizeof(struct sockaddr_storage);
123394960e5delphij
123494960e5delphij			socktemp = accept(sockdata, (struct sockaddr *) &saddr, &saddrlen);
123594960e5delphij
123619bb0b8hselasky			if (socktemp == INVALID_SOCKET)
123794960e5delphij			{
1238c2630c9philip				sock_geterror("accept()", fp->errbuf, PCAP_ERRBUF_SIZE);
123994960e5delphij				goto error;
124094960e5delphij			}
124194960e5delphij
124294960e5delphij			/* Now that I accepted the connection, the server socket is no longer needed */
124394960e5delphij			sock_close(sockdata, fp->errbuf, PCAP_ERRBUF_SIZE);
124494960e5delphij			sockdata = socktemp;
124594960e5delphij		}
124694960e5delphij	}
124794960e5delphij
124894960e5delphij	/* Let's save the socket of the data connection */
124919bb0b8hselasky	pr->rmt_sockdata = sockdata;
125094960e5delphij
125119bb0b8hselasky	/*
125219bb0b8hselasky	 * Set the size of the socket buffer for the data socket.
125319bb0b8hselasky	 * It has the same size as the local capture buffer used
125419bb0b8hselasky	 * on the other side of the connection.
125519bb0b8hselasky	 */
125619bb0b8hselasky	server_sockbufsize = ntohl(startcapreply.bufsize);
125794960e5delphij
125894960e5delphij	/* Let's get the actual size of the socket buffer */
125994960e5delphij	itemp = sizeof(sockbufsize);
126094960e5delphij
126194960e5delphij	res = getsockopt(sockdata, SOL_SOCKET, SO_RCVBUF, (char *)&sockbufsize, &itemp);
126294960e5delphij	if (res == -1)
126394960e5delphij	{
1264c2630c9philip		sock_geterror("pcap_startcapture_remote(): getsockopt() failed", fp->errbuf, PCAP_ERRBUF_SIZE);
1265c2630c9philip		goto error;
126694960e5delphij	}
126794960e5delphij
126894960e5delphij	/*
126919bb0b8hselasky	 * Warning: on some kernels (e.g. Linux), the size of the user
127019bb0b8hselasky	 * buffer does not take into account the pcap_header and such,
127119bb0b8hselasky	 * and it is set equal to the snaplen.
127219bb0b8hselasky	 *
127319bb0b8hselasky	 * In my view, this is wrong (the meaning of the bufsize became
127419bb0b8hselasky	 * a bit strange).  So, here bufsize is the whole size of the
127519bb0b8hselasky	 * user buffer.  In case the bufsize returned is too small,
127619bb0b8hselasky	 * let's adjust it accordingly.
127794960e5delphij	 */
127819bb0b8hselasky	if (server_sockbufsize <= (u_int) fp->snapshot)
127919bb0b8hselasky		server_sockbufsize += sizeof(struct pcap_pkthdr);
128094960e5delphij
128194960e5delphij	/* if the current socket buffer is smaller than the desired one */
128219bb0b8hselasky	if ((u_int) sockbufsize < server_sockbufsize)
128394960e5delphij	{
128419bb0b8hselasky		/*
128519bb0b8hselasky		 * Loop until the buffer size is OK or the original
128619bb0b8hselasky		 * socket buffer size is larger than this one.
128719bb0b8hselasky		 */
128819bb0b8hselasky		for (;;)
128994960e5delphij		{
129019bb0b8hselasky			res = setsockopt(sockdata, SOL_SOCKET, SO_RCVBUF,
129119bb0b8hselasky			    (char *)&(server_sockbufsize),
129219bb0b8hselasky			    sizeof(server_sockbufsize));
129394960e5delphij
129494960e5delphij			if (res == 0)
129594960e5delphij				break;
129694960e5delphij
129794960e5delphij			/*
129819bb0b8hselasky			 * If something goes wrong, halve the buffer size
129919bb0b8hselasky			 * (checking that it does not become smaller than
130019bb0b8hselasky			 * the current one).
130194960e5delphij			 */
130219bb0b8hselasky			server_sockbufsize /= 2;
130394960e5delphij
130419bb0b8hselasky			if ((u_int) sockbufsize >= server_sockbufsize)
130594960e5delphij			{
130619bb0b8hselasky				server_sockbufsize = sockbufsize;
130794960e5delphij				break;
130894960e5delphij			}
130994960e5delphij		}
131094960e5delphij	}
131194960e5delphij
131294960e5delphij	/*
131319bb0b8hselasky	 * Let's allocate the packet; this is required in order to put
131419bb0b8hselasky	 * the packet somewhere when extracting data from the socket.
131519bb0b8hselasky	 * Since buffering has already been done in the socket buffer,
131619bb0b8hselasky	 * here we need just a buffer whose size is equal to the
131719bb0b8hselasky	 * largest possible packet message for the snapshot size,
131819bb0b8hselasky	 * namely the length of the message header plus the length
131919bb0b8hselasky	 * of the packet header plus the snapshot length.
132094960e5delphij	 */
132119bb0b8hselasky	fp->bufsize = sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr) + fp->snapshot;
132294960e5delphij
132394960e5delphij	fp->buffer = (u_char *)malloc(fp->bufsize);
132494960e5delphij	if (fp->buffer == NULL)
132594960e5delphij	{
132619bb0b8hselasky		pcap_fmt_errmsg_for_errno(fp->errbuf, PCAP_ERRBUF_SIZE,
132719bb0b8hselasky		    errno, "malloc");
132894960e5delphij		goto error;
132994960e5delphij	}
133094960e5delphij
133119bb0b8hselasky	/*
133219bb0b8hselasky	 * The buffer is currently empty.
133319bb0b8hselasky	 */
133419bb0b8hselasky	fp->bp = fp->buffer;
133519bb0b8hselasky	fp->cc = 0;
133694960e5delphij
133719bb0b8hselasky	/* Discard the rest of the message. */
133819bb0b8hselasky	if (rpcap_discard(pr->rmt_sockctrl, plen, fp->errbuf) == -1)
1339c2630c9philip		goto error_nodiscard;
134094960e5delphij
134194960e5delphij	/*
134294960e5delphij	 * In case the user does not want to capture RPCAP packets, let's update the filter
134394960e5delphij	 * We have to update it here (instead of sending it into the 'StartCapture' message
134494960e5delphij	 * because when we generate the 'start capture' we do not know (yet) all the ports
134594960e5delphij	 * we're currently using.
134694960e5delphij	 */
134719bb0b8hselasky	if (pr->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP)
134894960e5delphij	{
134994960e5delphij		struct bpf_program fcode;
135094960e5delphij
135194960e5delphij		if (pcap_createfilter_norpcappkt(fp, &fcode) == -1)
135294960e5delphij			goto error;
135394960e5delphij
135419bb0b8hselasky		/* We cannot use 'pcap_setfilter_rpcap' because formally the capture has not been started yet */
135519bb0b8hselasky		/* (the 'pr->rmt_capstarted' variable will be updated some lines below) */
135694960e5delphij		if (pcap_updatefilter_remote(fp, &fcode) == -1)
135794960e5delphij			goto error;
135894960e5delphij
135994960e5delphij		pcap_freecode(&fcode);
136094960e5delphij	}
136194960e5delphij
136219bb0b8hselasky	pr->rmt_capstarted = 1;
136394960e5delphij	return 0;
136494960e5delphij
136594960e5delphijerror:
136694960e5delphij	/*
136794960e5delphij	 * When the connection has been established, we have to close it. So, at the
136894960e5delphij	 * beginning of this function, if an error occur we return immediately with
136994960e5delphij	 * a return NULL; when the connection is established, we have to come here
137094960e5delphij	 * ('goto error;') in order to close everything properly.
137194960e5delphij	 */
137294960e5delphij
137319bb0b8hselasky	/*
137419bb0b8hselasky	 * Discard the rest of the message.
137519bb0b8hselasky	 * We already reported an error; if this gets an error, just
137619bb0b8hselasky	 * drive on.
137719bb0b8hselasky	 */
137819bb0b8hselasky	(void)rpcap_discard(pr->rmt_sockctrl, plen, NULL);
137919bb0b8hselasky
138019bb0b8hselaskyerror_nodiscard:
138194960e5delphij	if ((sockdata) && (sockdata != -1))		/* we can be here because sockdata said 'error' */
138294960e5delphij		sock_close(sockdata, NULL, 0);
138394960e5delphij
138494960e5delphij	if (!active)
138519bb0b8hselasky		sock_close(pr->rmt_sockctrl, NULL, 0);
138619bb0b8hselasky
138719bb0b8hselasky	if (addrinfo != NULL)
138819bb0b8hselasky		freeaddrinfo(addrinfo);
138994960e5delphij
139094960e5delphij	/*
139194960e5delphij	 * We do not have to call pcap_close() here, because this function is always called
139294960e5delphij	 * by the user in case something bad happens
139394960e5delphij	 */
139419bb0b8hselasky#if 0
139519bb0b8hselasky	if (fp)
139619bb0b8hselasky	{
139719bb0b8hselasky		pcap_close(fp);
139819bb0b8hselasky		fp= NULL;
139919bb0b8hselasky	}
140019bb0b8hselasky#endif
140194960e5delphij
140294960e5delphij	return -1;
140394960e5delphij}
140494960e5delphij
140594960e5delphij/*
140619bb0b8hselasky * This function takes a bpf program and sends it to the other host.
140794960e5delphij *
140894960e5delphij * This function can be called in two cases:
140919bb0b8hselasky * - pcap_startcapture_remote() is called (we have to send the filter
141019bb0b8hselasky *   along with the 'start capture' command)
141119bb0b8hselasky * - we want to udpate the filter during a capture (i.e. pcap_setfilter()
141219bb0b8hselasky *   after the capture has been started)
141394960e5delphij *
141419bb0b8hselasky * This function serializes the filter into the sending buffer ('sendbuf',
141519bb0b8hselasky * passed as a parameter) and return back. It does not send anything on
141619bb0b8hselasky * the network.
141794960e5delphij *
141894960e5delphij * \param fp: the pcap_t descriptor of the device currently opened.
141994960e5delphij *
142094960e5delphij * \param sendbuf: the buffer on which the serialized data has to copied.
142194960e5delphij *
142294960e5delphij * \param sendbufidx: it is used to return the abounf of bytes copied into the buffer.
142394960e5delphij *
142494960e5delphij * \param prog: the bpf program we have to copy.
142594960e5delphij *
142694960e5delphij * \return '0' if everything is fine, '-1' otherwise. The error message (if one)
142794960e5delphij * is returned into the 'errbuf' field of the pcap_t structure.
142894960e5delphij */
142994960e5delphijstatic int pcap_pack_bpffilter(pcap_t *fp, char *sendbuf, int *sendbufidx, struct bpf_program *prog)
143094960e5delphij{
143194960e5delphij	struct rpcap_filter *filter;
143294960e5delphij	struct rpcap_filterbpf_insn *insn;
143394960e5delphij	struct bpf_insn *bf_insn;
143494960e5delphij	struct bpf_program fake_prog;		/* To be used just in case the user forgot to set a filter */
143594960e5delphij	unsigned int i;
143694960e5delphij
143794960e5delphij	if (prog->bf_len == 0)	/* No filters have been specified; so, let's apply a "fake" filter */
143894960e5delphij	{
143994960e5delphij		if (pcap_compile(fp, &fake_prog, NULL /* buffer */, 1, 0) == -1)
144094960e5delphij			return -1;
144194960e5delphij
144294960e5delphij		prog = &fake_prog;
144394960e5delphij	}
144494960e5delphij
144594960e5delphij	filter = (struct rpcap_filter *) sendbuf;
144694960e5delphij
144794960e5delphij	if (sock_bufferize(NULL, sizeof(struct rpcap_filter), NULL, sendbufidx,
144894960e5delphij		RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE))
144994960e5delphij		return -1;
145094960e5delphij
145194960e5delphij	filter->filtertype = htons(RPCAP_UPDATEFILTER_BPF);
145294960e5delphij	filter->nitems = htonl((int32)prog->bf_len);
145394960e5delphij
145494960e5delphij	if (sock_bufferize(NULL, prog->bf_len * sizeof(struct rpcap_filterbpf_insn),
145594960e5delphij		NULL, sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE))
145694960e5delphij		return -1;
145794960e5delphij
145894960e5delphij	insn = (struct rpcap_filterbpf_insn *) (filter + 1);
145994960e5delphij	bf_insn = prog->bf_insns;
146094960e5delphij
146194960e5delphij	for (i = 0; i < prog->bf_len; i++)
146294960e5delphij	{
146394960e5delphij		insn->code = htons(bf_insn->code);
146494960e5delphij		insn->jf = bf_insn->jf;
146594960e5delphij		insn->jt = bf_insn->jt;
146694960e5delphij		insn->k = htonl(bf_insn->k);
146794960e5delphij
146894960e5delphij		insn++;
146994960e5delphij		bf_insn++;
147094960e5delphij	}
147194960e5delphij
147294960e5delphij	return 0;
147394960e5delphij}
147494960e5delphij
147519bb0b8hselasky/*
147619bb0b8hselasky * This function updates a filter on a remote host.
147794960e5delphij *
147819bb0b8hselasky * It is called when the user wants to update a filter.
147919bb0b8hselasky * In case we're capturing from the network, it sends the filter to our
148019bb0b8hselasky * peer.
148119bb0b8hselasky * This function is *not* called automatically when the user calls
148219bb0b8hselasky * pcap_setfilter().
148394960e5delphij * There will be two cases:
148419bb0b8hselasky * - the capture has been started: in this case, pcap_setfilter_rpcap()
148519bb0b8hselasky *   calls pcap_updatefilter_remote()
148619bb0b8hselasky * - the capture has not started yet: in this case, pcap_setfilter_rpcap()
148719bb0b8hselasky *   stores the filter into the pcap_t structure, and then the filter is
148819bb0b8hselasky *   sent with pcap_startcap().
148919bb0b8hselasky *
149019bb0b8hselasky * WARNING This function *does not* clear the packet currently into the
149119bb0b8hselasky * buffers. Therefore, the user has to expect to receive some packets
149219bb0b8hselasky * that are related to the previous filter.  If you want to discard all
149319bb0b8hselasky * the packets before applying a new filter, you have to close the
149419bb0b8hselasky * current capture session and start a new one.
149519bb0b8hselasky *
149619bb0b8hselasky * XXX - we really should have pcap_setfilter() always discard packets
149719bb0b8hselasky * received with the old filter, and have a separate pcap_setfilter_noflush()
149819bb0b8hselasky * function that doesn't discard any packets.
149994960e5delphij */
150094960e5delphijstatic int pcap_updatefilter_remote(pcap_t *fp, struct bpf_program *prog)
150194960e5delphij{
150219bb0b8hselasky	struct pcap_rpcap *pr = fp->priv;	/* structure used when doing a remote live capture */
150319bb0b8hselasky	char sendbuf[RPCAP_NETBUF_SIZE];	/* temporary buffer in which data to be sent is buffered */
150419bb0b8hselasky	int sendbufidx = 0;			/* index which keeps the number of bytes currently buffered */
150594960e5delphij	struct rpcap_header header;		/* To keep the reply message */
150694960e5delphij
150794960e5delphij	if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
150894960e5delphij		RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE))
150994960e5delphij		return -1;
151094960e5delphij
151119bb0b8hselasky	rpcap_createhdr((struct rpcap_header *) sendbuf,
151219bb0b8hselasky	    pr->protocol_version, RPCAP_MSG_UPDATEFILTER_REQ, 0,
151319bb0b8hselasky	    sizeof(struct rpcap_filter) + prog->bf_len * sizeof(struct rpcap_filterbpf_insn));
151494960e5delphij
151594960e5delphij	if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, prog))
151694960e5delphij		return -1;
151794960e5delphij
151819bb0b8hselasky	if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
151919bb0b8hselasky	    PCAP_ERRBUF_SIZE) < 0)
152094960e5delphij		return -1;
152194960e5delphij
152219bb0b8hselasky	/* Receive and process the reply message header. */
152319bb0b8hselasky	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
152419bb0b8hselasky	    RPCAP_MSG_UPDATEFILTER_REQ, &header, fp->errbuf) == -1)
152594960e5delphij		return -1;
152694960e5delphij
152719bb0b8hselasky	/*
152819bb0b8hselasky	 * It shouldn't have any contents; discard it if it does.
152919bb0b8hselasky	 */
153019bb0b8hselasky	if (rpcap_discard(pr->rmt_sockctrl, header.plen, fp->errbuf) == -1)
153119bb0b8hselasky		return -1;
153294960e5delphij
153319bb0b8hselasky	return 0;
153419bb0b8hselasky}
153594960e5delphij
153619bb0b8hselaskystatic void
153719bb0b8hselaskypcap_save_current_filter_rpcap(pcap_t *fp, const char *filter)
153819bb0b8hselasky{
153919bb0b8hselasky	struct pcap_rpcap *pr = fp->priv;	/* structure used when doing a remote live capture */
154094960e5delphij
154119bb0b8hselasky	/*
154219bb0b8hselasky	 * Check if:
154319bb0b8hselasky	 *  - We are on an remote capture
154419bb0b8hselasky	 *  - we do not want to capture RPCAP traffic
154519bb0b8hselasky	 *
154619bb0b8hselasky	 * If so, we have to save the current filter, because we have to
154719bb0b8hselasky	 * add some piece of stuff later
154819bb0b8hselasky	 */
154919bb0b8hselasky	if (pr->rmt_clientside &&
155019bb0b8hselasky	    (pr->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP))
155194960e5delphij	{
155219bb0b8hselasky		if (pr->currentfilter)
155319bb0b8hselasky			free(pr->currentfilter);
155494960e5delphij
155519bb0b8hselasky		if (filter == NULL)
155619bb0b8hselasky			filter = "";
155719bb0b8hselasky
155819bb0b8hselasky		pr->currentfilter = strdup(filter);
155919bb0b8hselasky	}
156094960e5delphij}
156194960e5delphij
156294960e5delphij/*
156319bb0b8hselasky * This function sends a filter to a remote host.
156494960e5delphij *
156594960e5delphij * This function is called when the user wants to set a filter.
156619bb0b8hselasky * It sends the filter to our peer.
156719bb0b8hselasky * This function is called automatically when the user calls pcap_setfilter().
156894960e5delphij *
156919bb0b8hselasky * Parameters and return values are exactly the same of pcap_setfilter().
157094960e5delphij */
157119bb0b8hselaskystatic int pcap_setfilter_rpcap(pcap_t *fp, struct bpf_program *prog)
157294960e5delphij{
157319bb0b8hselasky	struct pcap_rpcap *pr = fp->priv;	/* structure used when doing a remote live capture */
157494960e5delphij
157519bb0b8hselasky	if (!pr->rmt_capstarted)
157694960e5delphij	{
157794960e5delphij		/* copy filter into the pcap_t structure */
157894960e5delphij		if (install_bpf_program(fp, prog) == -1)
157994960e5delphij			return -1;
158094960e5delphij		return 0;
158194960e5delphij	}
158294960e5delphij
158394960e5delphij	/* we have to update a filter during run-time */
158494960e5delphij	if (pcap_updatefilter_remote(fp, prog))
158594960e5delphij		return -1;
158694960e5delphij
158794960e5delphij	return 0;
158894960e5delphij}
158994960e5delphij
159094960e5delphij/*
159119bb0b8hselasky * This function updates the current filter in order not to capture rpcap
159219bb0b8hselasky * packets.
159394960e5delphij *
159494960e5delphij * This function is called *only* when the user wants exclude RPCAP packets
159594960e5delphij * related to the current session from the captured packets.
159694960e5delphij *
159794960e5delphij * \return '0' if everything is fine, '-1' otherwise. The error message (if one)
159894960e5delphij * is returned into the 'errbuf' field of the pcap_t structure.
159994960e5delphij */
160094960e5delphijstatic int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog)
160194960e5delphij{
160219bb0b8hselasky	struct pcap_rpcap *pr = fp->priv;	/* structure used when doing a remote live capture */
160394960e5delphij	int RetVal = 0;
160494960e5delphij
160594960e5delphij	/* We do not want to capture our RPCAP traffic. So, let's update the filter */
160619bb0b8hselasky	if (pr->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP)
160794960e5delphij	{
160894960e5delphij		struct sockaddr_storage saddr;		/* temp, needed to retrieve the network data port chosen on the local machine */
160994960e5delphij		socklen_t saddrlen;					/* temp, needed to retrieve the network data port chosen on the local machine */
161094960e5delphij		char myaddress[128];
161194960e5delphij		char myctrlport[128];
161294960e5delphij		char mydataport[128];
161394960e5delphij		char peeraddress[128];
161494960e5delphij		char peerctrlport[128];
161594960e5delphij		char *newfilter;
161694960e5delphij
161719bb0b8hselasky		/* Get the name/port of our peer */
161894960e5delphij		saddrlen = sizeof(struct sockaddr_storage);
161919bb0b8hselasky		if (getpeername(pr->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1)
162094960e5delphij		{
1621c2630c9philip			sock_geterror("getpeername()", fp->errbuf, PCAP_ERRBUF_SIZE);
162294960e5delphij			return -1;
162394960e5delphij		}
162494960e5delphij
162594960e5delphij		if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peeraddress,
162694960e5delphij			sizeof(peeraddress), peerctrlport, sizeof(peerctrlport), NI_NUMERICHOST | NI_NUMERICSERV))
162794960e5delphij		{
1628c2630c9philip			sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE);
162994960e5delphij			return -1;
163094960e5delphij		}
163194960e5delphij
163294960e5delphij		/* We cannot check the data port, because this is available only in case of TCP sockets */
163394960e5delphij		/* Get the name/port of the current host */
163419bb0b8hselasky		if (getsockname(pr->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1)
163594960e5delphij		{
1636c2630c9philip			sock_geterror("getsockname()", fp->errbuf, PCAP_ERRBUF_SIZE);
163794960e5delphij			return -1;
163894960e5delphij		}
163994960e5delphij
164094960e5delphij		/* Get the local port the system picked up */
164194960e5delphij		if (getnameinfo((struct sockaddr *) &saddr, saddrlen, myaddress,
164294960e5delphij			sizeof(myaddress), myctrlport, sizeof(myctrlport), NI_NUMERICHOST | NI_NUMERICSERV))
164394960e5delphij		{
1644c2630c9philip			sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE);
164594960e5delphij			return -1;
164694960e5delphij		}
164794960e5delphij
164894960e5delphij		/* Let's now check the data port */
164919bb0b8hselasky		if (getsockname(pr->rmt_sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1)
165094960e5delphij		{
1651c2630c9philip			sock_geterror("getsockname()", fp->errbuf, PCAP_ERRBUF_SIZE);
165294960e5delphij			return -1;
165394960e5delphij		}
165494960e5delphij
165594960e5delphij		/* Get the local port the system picked up */
165694960e5delphij		if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL, 0, mydataport, sizeof(mydataport), NI_NUMERICSERV))
165794960e5delphij		{
1658c2630c9philip			sock_geterror("getnameinfo()", fp->errbuf, PCAP_ERRBUF_SIZE);
165994960e5delphij			return -1;
166094960e5delphij		}
166194960e5delphij
1662c2630c9philip		if (pr->currentfilter && pr->currentfilter[0] != '\0')
166394960e5delphij		{
1664c2630c9philip			/*
1665c2630c9philip			 * We have a current filter; add items to it to
1666c2630c9philip			 * filter out this rpcap session.
1667c2630c9philip			 */
1668c2630c9philip			if (pcap_asprintf(&newfilter,
1669c2630c9philip			    "(%s) and not (host %s and host %s and port %s and port %s) and not (host %s and host %s and port %s)",
1670c2630c9philip			    pr->currentfilter, myaddress, peeraddress,
1671c2630c9philip			    myctrlport, peerctrlport, myaddress, peeraddress,
1672c2630c9philip			    mydataport) == -1)
1673c2630c9philip			{
1674c2630c9philip				/* Failed. */
1675c2630c9philip				pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
1676c2630c9philip				    "Can't allocate memory for new filter");
1677c2630c9philip				return -1;
1678c2630c9philip			}
167994960e5delphij		}
168094960e5delphij		else
168194960e5delphij		{
1682c2630c9philip			/*
1683c2630c9philip			 * We have no current filter; construct a filter to
1684c2630c9philip			 * filter out this rpcap session.
1685c2630c9philip			 */
1686c2630c9philip			if (pcap_asprintf(&newfilter,
1687c2630c9philip			    "not (host %s and host %s and port %s and port %s) and not (host %s and host %s and port %s)",
1688c2630c9philip			    myaddress, peeraddress, myctrlport, peerctrlport,
1689c2630c9philip			    myaddress, peeraddress, mydataport) == -1)
1690c2630c9philip			{
1691c2630c9philip				/* Failed. */
1692c2630c9philip				pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
1693c2630c9philip				    "Can't allocate memory for new filter");
1694c2630c9philip				return -1;
1695c2630c9philip			}
169694960e5delphij		}
169794960e5delphij
169819bb0b8hselasky		/*
169919bb0b8hselasky		 * This is only an hack to prevent the save_current_filter
170019bb0b8hselasky		 * routine, which will be called when we call pcap_compile(),
170119bb0b8hselasky		 * from saving the modified filter.
170219bb0b8hselasky		 */
170319bb0b8hselasky		pr->rmt_clientside = 0;
170494960e5delphij
170594960e5delphij		if (pcap_compile(fp, prog, newfilter, 1, 0) == -1)
170694960e5delphij			RetVal = -1;
170794960e5delphij
170819bb0b8hselasky		/* Undo the hack. */
170919bb0b8hselasky		pr->rmt_clientside = 1;
171094960e5delphij
171194960e5delphij		free(newfilter);
171294960e5delphij	}
171394960e5delphij
171494960e5delphij	return RetVal;
171594960e5delphij}
171694960e5delphij
171794960e5delphij/*
171819bb0b8hselasky * This function sets sampling parameters in the remote host.
171994960e5delphij *
172019bb0b8hselasky * It is called when the user wants to set activate sampling on the
172119bb0b8hselasky * remote host.
172294960e5delphij *
172394960e5delphij * Sampling parameters are defined into the 'pcap_t' structure.
172494960e5delphij *
172594960e5delphij * \param p: the pcap_t descriptor of the device currently opened.
172694960e5delphij *
172719bb0b8hselasky * \return '0' if everything is OK, '-1' is something goes wrong. The
172819bb0b8hselasky * error message is returned in the 'errbuf' member of the pcap_t structure.
172994960e5delphij */
173019bb0b8hselaskystatic int pcap_setsampling_remote(pcap_t *fp)
173194960e5delphij{
173219bb0b8hselasky	struct pcap_rpcap *pr = fp->priv;	/* structure used when doing a remote live capture */
173394960e5delphij	char sendbuf[RPCAP_NETBUF_SIZE];/* temporary buffer in which data to be sent is buffered */
173419bb0b8hselasky	int sendbufidx = 0;			/* index which keeps the number of bytes currently buffered */
173594960e5delphij	struct rpcap_header header;		/* To keep the reply message */
173694960e5delphij	struct rpcap_sampling *sampling_pars;	/* Structure that is needed to send sampling parameters to the remote host */
173794960e5delphij
173894960e5delphij	/* If no samping is requested, return 'ok' */
173919bb0b8hselasky	if (fp->rmt_samp.method == PCAP_SAMP_NOSAMP)
174094960e5delphij		return 0;
174194960e5delphij
174219bb0b8hselasky	/*
174319bb0b8hselasky	 * Check for sampling parameters that don't fit in a message.
174419bb0b8hselasky	 * We'll let the server complain about invalid parameters
174519bb0b8hselasky	 * that do fit into the message.
174619bb0b8hselasky	 */
174719bb0b8hselasky	if (fp->rmt_samp.method < 0 || fp->rmt_samp.method > 255) {
174819bb0b8hselasky		pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
174919bb0b8hselasky		    "Invalid sampling method %d", fp->rmt_samp.method);
175019bb0b8hselasky		return -1;
175119bb0b8hselasky	}
175219bb0b8hselasky	if (fp->rmt_samp.value < 0 || fp->rmt_samp.value > 65535) {
175319bb0b8hselasky		pcap_snprintf(fp->errbuf, PCAP_ERRBUF_SIZE,
175419bb0b8hselasky		    "Invalid sampling value %d", fp->rmt_samp.value);
175519bb0b8hselasky		return -1;
175619bb0b8hselasky	}
175719bb0b8hselasky
175894960e5delphij	if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
175919bb0b8hselasky		&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE))
176094960e5delphij		return -1;
176194960e5delphij
176219bb0b8hselasky	rpcap_createhdr((struct rpcap_header *) sendbuf,
176319bb0b8hselasky	    pr->protocol_version, RPCAP_MSG_SETSAMPLING_REQ, 0,
176419bb0b8hselasky	    sizeof(struct rpcap_sampling));
176594960e5delphij
176694960e5delphij	/* Fill the structure needed to open an adapter remotely */
176794960e5delphij	sampling_pars = (struct rpcap_sampling *) &sendbuf[sendbufidx];
176894960e5delphij
176994960e5delphij	if (sock_bufferize(NULL, sizeof(struct rpcap_sampling), NULL,
177019bb0b8hselasky		&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE))
177194960e5delphij		return -1;
177294960e5delphij
177394960e5delphij	memset(sampling_pars, 0, sizeof(struct rpcap_sampling));
177494960e5delphij
177519bb0b8hselasky	sampling_pars->method = (uint8)fp->rmt_samp.method;
177619bb0b8hselasky	sampling_pars->value = (uint16)htonl(fp->rmt_samp.value);
177794960e5delphij
177819bb0b8hselasky	if (sock_send(pr->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf,
177919bb0b8hselasky	    PCAP_ERRBUF_SIZE) < 0)
178094960e5delphij		return -1;
178194960e5delphij
178219bb0b8hselasky	/* Receive and process the reply message header. */
178319bb0b8hselasky	if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->protocol_version,
178419bb0b8hselasky	    RPCAP_MSG_SETSAMPLING_REQ, &header, fp->errbuf) == -1)
178594960e5delphij		return -1;
178694960e5delphij
178719bb0b8hselasky	/*
178819bb0b8hselasky	 * It shouldn't have any contents; discard it if it does.
178919bb0b8hselasky	 */
179019bb0b8hselasky	if (rpcap_discard(pr->rmt_sockctrl, header.plen, fp->errbuf) == -1)
179119bb0b8hselasky		return -1;
179294960e5delphij
179394960e5delphij	return 0;
179494960e5delphij}
179594960e5delphij
179694960e5delphij/*********************************************************
179794960e5delphij *                                                       *
179894960e5delphij * Miscellaneous functions                               *
179994960e5delphij *                                                       *
180094960e5delphij *********************************************************/
180194960e5delphij
180219bb0b8hselasky/*
180319bb0b8hselasky * This function performs authentication and protocol version
1804c2630c9philip * negotiation.  It is required in order to open the connection
1805c2630c9philip * with the other end party.
1806c2630c9philip *
1807c2630c9philip * It sends authentication parameters on the control socket and
1808c2630c9philip * reads the reply.  If the reply is a success indication, it
1809c2630c9philip * checks whether the reply includes minimum and maximum supported
1810c2630c9philip * versions from the server; if not, it assumes both are 0, as
1811c2630c9philip * that means it's an older server that doesn't return supported
1812c2630c9philip * version numbers in authentication replies, so it only supports
1813c2630c9philip * version 0.  It then tries to determine the maximum version
1814c2630c9philip * supported both by us and by the server.  If it can find such a
1815c2630c9philip * version, it sets us up to use that version; otherwise, it fails,
1816c2630c9philip * indicating that there is no version supported by us and by the
1817c2630c9philip * server.
181894960e5delphij *
181994960e5delphij * \param sock: the socket we are currently using.
182094960e5delphij *
1821c2630c9philip * \param ver: pointer to variable to which to set the protocol version
1822c2630c9philip * number we selected.
182394960e5delphij *
182419bb0b8hselasky * \param auth: authentication parameters that have to be sent.
182594960e5delphij *
182619bb0b8hselasky * \param errbuf: a pointer to a user-allocated buffer (of size
182719bb0b8hselasky * PCAP_ERRBUF_SIZE) that will contain the error message (in case there
182819bb0b8hselasky * is one). It could be a network problem or the fact that the authorization
182919bb0b8hselasky * failed.
183094960e5delphij *
183119bb0b8hselasky * \return '0' if everything is fine, '-1' for an error.  For errors,
183219bb0b8hselasky * an error message string is returned in the 'errbuf' variable.
183394960e5delphij */
183419bb0b8hselaskystatic int rpcap_doauth(SOCKET sockctrl, uint8 *ver, struct pcap_rmtauth *auth, char *errbuf)
183594960e5delphij{
183694960e5delphij	char sendbuf[RPCAP_NETBUF_SIZE];	/* temporary buffer in which data that has to be sent is buffered */
183719bb0b8hselasky	int sendbufidx = 0;			/* index which keeps the number of bytes currently buffered */
183819bb0b8hselasky	uint16 length;				/* length of the payload of this message */
183994960e5delphij	struct rpcap_auth *rpauth;
184094960e5delphij	uint16 auth_type;
184194960e5delphij	struct rpcap_header header;
184219bb0b8hselasky	size_t str_length;
1843c2630c9philip	uint32 plen;
1844c2630c9philip	struct rpcap_authreply authreply;	/* authentication reply message */
1845c2630c9philip	uint8 ourvers;
184694960e5delphij
184794960e5delphij	if (auth)
184894960e5delphij	{
184994960e5delphij		switch (auth->type)
185094960e5delphij		{
185194960e5delphij		case RPCAP_RMTAUTH_NULL:
185294960e5delphij			length = sizeof(struct rpcap_auth);
185394960e5delphij			break;
185494960e5delphij
185594960e5delphij		case RPCAP_RMTAUTH_PWD:
185694960e5delphij			length = sizeof(struct rpcap_auth);
185719bb0b8hselasky			if (auth->username)
185819bb0b8hselasky			{
185919bb0b8hselasky				str_length = strlen(auth->username);
186019bb0b8hselasky				if (str_length > 65535)
186119bb0b8hselasky				{
186219bb0b8hselasky					pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "User name is too long (> 65535 bytes)");
186319bb0b8hselasky					return -1;
186419bb0b8hselasky				}
186519bb0b8hselasky				length += (uint16)str_length;
186619bb0b8hselasky			}
186719bb0b8hselasky			if (auth->password)
186819bb0b8hselasky			{
186919bb0b8hselasky				str_length = strlen(auth->password);
187019bb0b8hselasky				if (str_length > 65535)
187119bb0b8hselasky				{
187219bb0b8hselasky					pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Password is too long (> 65535 bytes)");
187319bb0b8hselasky					return -1;
187419bb0b8hselasky				}
187519bb0b8hselasky				length += (uint16)str_length;
187619bb0b8hselasky			}
187794960e5delphij			break;
187894960e5delphij
187994960e5delphij		default:
188094960e5delphij			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized.");
188194960e5delphij			return -1;
188294960e5delphij		}
188319bb0b8hselasky
188419bb0b8hselasky		auth_type = (uint16)auth->type;
188594960e5delphij	}
188694960e5delphij	else
188794960e5delphij	{
188894960e5delphij		auth_type = RPCAP_RMTAUTH_NULL;
188994960e5delphij		length = sizeof(struct rpcap_auth);
189094960e5delphij	}
189194960e5delphij
189294960e5delphij	if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
189394960e5delphij		&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE))
189494960e5delphij		return -1;
189594960e5delphij
1896c2630c9philip	rpcap_createhdr((struct rpcap_header *) sendbuf, 0,
189719bb0b8hselasky	    RPCAP_MSG_AUTH_REQ, 0, length);
189894960e5delphij
189994960e5delphij	rpauth = (struct rpcap_auth *) &sendbuf[sendbufidx];
190094960e5delphij
190194960e5delphij	if (sock_bufferize(NULL, sizeof(struct rpcap_auth), NULL,
190294960e5delphij		&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE))
190394960e5delphij		return -1;
190494960e5delphij
190594960e5delphij	memset(rpauth, 0, sizeof(struct rpcap_auth));
190694960e5delphij
190794960e5delphij	rpauth->type = htons(auth_type);
190894960e5delphij
190994960e5delphij	if (auth_type == RPCAP_RMTAUTH_PWD)
191094960e5delphij	{
191194960e5delphij		if (auth->username)
191219bb0b8hselasky			rpauth->slen1 = (uint16)strlen(auth->username);
191394960e5delphij		else
191494960e5delphij			rpauth->slen1 = 0;
191594960e5delphij
191694960e5delphij		if (sock_bufferize(auth->username, rpauth->slen1, sendbuf,
191794960e5delphij			&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE))
191894960e5delphij			return -1;
191994960e5delphij
192094960e5delphij		if (auth->password)
192119bb0b8hselasky			rpauth->slen2 = (uint16)strlen(auth->password);
192294960e5delphij		else
192394960e5delphij			rpauth->slen2 = 0;
192494960e5delphij
192594960e5delphij		if (sock_bufferize(auth->password, rpauth->slen2, sendbuf,
192694960e5delphij			&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE))
192794960e5delphij			return -1;
192894960e5delphij
192994960e5delphij		rpauth->slen1 = htons(rpauth->slen1);
193094960e5delphij		rpauth->slen2 = htons(rpauth->slen2);
193194960e5delphij	}
193294960e5delphij
1933c2630c9philip	if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf,
1934c2630c9philip	    PCAP_ERRBUF_SIZE) < 0)
193594960e5delphij		return -1;
193694960e5delphij
1937c2630c9philip	/* Receive and process the reply message header */
1938c2630c9philip	if (rpcap_process_msg_header(sockctrl, 0, RPCAP_MSG_AUTH_REQ,
1939c2630c9philip	    &header, errbuf) == -1)
194094960e5delphij		return -1;
194194960e5delphij
1942c2630c9philip	/*
1943c2630c9philip	 * OK, it's an authentication reply, so we're logged in.
1944c2630c9philip	 *
1945c2630c9philip	 * Did it send any additional information?
1946c2630c9philip	 */
1947c2630c9philip	plen = header.plen;
1948c2630c9philip	if (plen != 0)
194994960e5delphij	{
1950c2630c9philip		/* Yes - is it big enough to be version information? */
1951c2630c9philip		if (plen < sizeof(struct rpcap_authreply))
195294960e5delphij		{
1953c2630c9philip			/* No - discard it and fail. */
1954c2630c9philip			(void)rpcap_discard(sockctrl, plen, NULL);
1955c2630c9philip			return -1;
1956c2630c9philip		}
195794960e5delphij
1958c2630c9philip		/* Read the reply body */
1959c2630c9philip		if (rpcap_recv(sockctrl, (char *)&authreply,
1960c2630c9philip		    sizeof(struct rpcap_authreply), &plen, errbuf) == -1)
1961c2630c9philip		{
1962c2630c9philip			(void)rpcap_discard(sockctrl, plen, NULL);
1963c2630c9philip			return -1;
196494960e5delphij		}
196594960e5delphij
1966c2630c9philip		/* Discard the rest of the message, if there is any. */
1967c2630c9philip		if (rpcap_discard(sockctrl, plen, errbuf) == -1)
1968c2630c9philip			return -1;
1969c2630c9philip
197019bb0b8hselasky		/*
1971c2630c9philip		 * Check the minimum and maximum versions for sanity;
1972c2630c9philip		 * the minimum must be <= the maximum.
197319bb0b8hselasky		 */
1974c2630c9philip		if (authreply.minvers > authreply.maxvers)
1975c2630c9philip		{
1976c2630c9philip			/*
1977c2630c9philip			 * Bogus - give up on this server.
1978c2630c9philip			 */
1979c2630c9philip			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
1980c2630c9philip			    "The server's minimum supported protocol version is greater than its maximum supported protocol version");
1981c2630c9philip			return -1;
1982c2630c9philip		}
1983c2630c9philip	}
1984c2630c9philip	else
1985c2630c9philip	{
1986c2630c9philip		/* No - it supports only version 0. */
1987c2630c9philip		authreply.minvers = 0;
1988c2630c9philip		authreply.maxvers = 0;
198994960e5delphij	}
199094960e5delphij
199119bb0b8hselasky	/*
1992c2630c9philip	 * OK, let's start with the maximum version the server supports.
199319bb0b8hselasky	 */
1994c2630c9philip	ourvers = authreply.maxvers;
1995c2630c9philip
1996c2630c9philip#if RPCAP_MIN_VERSION != 0
1997c2630c9philip	/*
1998c2630c9philip	 * If that's less than the minimum version we support, we
1999c2630c9philip	 * can't communicate.
2000c2630c9philip	 */
2001c2630c9philip	if (ourvers < RPCAP_MIN_VERSION)
2002c2630c9philip		goto novers;
2003c2630c9philip#endif
2004c2630c9philip
2005c2630c9philip	/*
2006c2630c9philip	 * If that's greater than the maximum version we support,
2007c2630c9philip	 * choose the maximum version we support.
2008c2630c9philip	 */
2009c2630c9philip	if (ourvers > RPCAP_MAX_VERSION)
2010c2630c9philip	{
2011c2630c9philip		ourvers = RPCAP_MAX_VERSION;
201219bb0b8hselasky
2013c2630c9philip		/*
2014c2630c9philip		 * If that's less than the minimum version they
2015c2630c9philip		 * support, we can't communicate.
2016c2630c9philip		 */
2017c2630c9philip		if (ourvers < authreply.minvers)
2018c2630c9philip			goto novers;
2019c2630c9philip	}
2020c2630c9philip
2021c2630c9philip	*ver = ourvers;
202294960e5delphij	return 0;
2023c2630c9philip
2024c2630c9philipnovers:
2025c2630c9philip	/*
2026c2630c9philip	 * There is no version we both support; that is a fatal error.
2027c2630c9philip	 */
2028c2630c9philip	pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
2029c2630c9philip	    "The server doesn't support any protocol version that we support");
2030c2630c9philip	return -1;
203194960e5delphij}
203294960e5delphij
203319bb0b8hselasky/* We don't currently support non-blocking mode. */
203419bb0b8hselaskystatic int
203519bb0b8hselaskypcap_getnonblock_rpcap(pcap_t *p)
203619bb0b8hselasky{
203719bb0b8hselasky	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
203819bb0b8hselasky	    "Non-blocking mode isn't supported for capturing remotely with rpcap");
203919bb0b8hselasky	return (-1);
204019bb0b8hselasky}
204119bb0b8hselasky
204219bb0b8hselaskystatic int
204319bb0b8hselaskypcap_setnonblock_rpcap(pcap_t *p, int nonblock _U_)
204419bb0b8hselasky{
204519bb0b8hselasky	pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
204619bb0b8hselasky	    "Non-blocking mode isn't supported for capturing remotely with rpcap");
204719bb0b8hselasky	return (-1);
204819bb0b8hselasky}
204919bb0b8hselasky
2050c2630c9philipstatic int
2051c2630c9philiprpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
2052c2630c9philip    int *activep, SOCKET *sockctrlp, uint8 *protocol_versionp,
2053c2630c9philip    char *host, char *port, char *iface, char *errbuf)
2054c2630c9philip{
2055c2630c9philip	int type;
2056c2630c9philip	struct activehosts *activeconn;		/* active connection, if there is one */
2057c2630c9philip	int error;				/* 1 if rpcap_remoteact_getsock got an error */
2058c2630c9philip
2059c2630c9philip	/*
2060c2630c9philip	 * Determine the type of the source (NULL, file, local, remote).
2061c2630c9philip	 * You must have a valid source string even if we're in active mode,
2062c2630c9philip	 * because otherwise the call to the following function will fail.
2063c2630c9philip	 */
2064c2630c9philip	if (pcap_parsesrcstr(source, &type, host, port, iface, errbuf) == -1)
2065c2630c9philip		return -1;
2066c2630c9philip
2067c2630c9philip	/*
2068c2630c9philip	 * It must be remote.
2069c2630c9philip	 */
2070c2630c9philip	if (type != PCAP_SRC_IFREMOTE)
2071c2630c9philip	{
2072c2630c9philip		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
2073c2630c9philip		    "Non-remote interface passed to remote capture routine");
2074c2630c9philip		return -1;
2075c2630c9philip	}
2076c2630c9philip
2077c2630c9philip	/* Warning: this call can be the first one called by the user. */
2078c2630c9philip	/* For this reason, we have to initialize the WinSock support. */
2079c2630c9philip	if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
2080c2630c9philip		return -1;
2081c2630c9philip
2082c2630c9philip	/* Check for active mode */
2083c2630c9philip	activeconn = rpcap_remoteact_getsock(host, &error, errbuf);
2084c2630c9philip	if (activeconn != NULL)
2085c2630c9philip	{
2086c2630c9philip		*activep = 1;
2087c2630c9philip		*sockctrlp = activeconn->sockctrl;
2088c2630c9philip		*protocol_versionp = activeconn->protocol_version;
2089c2630c9philip	}
2090c2630c9philip	else
2091c2630c9philip	{
2092c2630c9philip		*activep = 0;
2093c2630c9philip		struct addrinfo hints;		/* temp variable needed to resolve hostnames into to socket representation */
2094c2630c9philip		struct addrinfo *addrinfo;	/* temp variable needed to resolve hostnames into to socket representation */
2095c2630c9philip
2096c2630c9philip		if (error)
2097c2630c9philip		{
2098c2630c9philip			/*
2099c2630c9philip			 * Call failed.
2100c2630c9philip			 */
2101c2630c9philip			return -1;
2102c2630c9philip		}
2103c2630c9philip
2104c2630c9philip		/*
2105c2630c9philip		 * We're not in active mode; let's try to open a new
2106c2630c9philip		 * control connection.
2107c2630c9philip		 */
2108c2630c9philip		memset(&hints, 0, sizeof(struct addrinfo));
2109c2630c9philip		hints.ai_family = PF_UNSPEC;
2110c2630c9philip		hints.ai_socktype = SOCK_STREAM;
2111c2630c9philip
2112c2630c9philip		if (port[0] == 0)
2113c2630c9philip		{
2114c2630c9philip			/* the user chose not to specify the port */
2115c2630c9philip			if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT,
2116c2630c9philip			    &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
2117c2630c9philip				return -1;
2118c2630c9philip		}
2119c2630c9philip		else
2120c2630c9philip		{
2121c2630c9philip			if (sock_initaddress(host, port, &hints, &addrinfo,
2122c2630c9philip			    errbuf, PCAP_ERRBUF_SIZE) == -1)
2123c2630c9philip				return -1;
2124c2630c9philip		}
2125c2630c9philip
2126c2630c9philip		if ((*sockctrlp = sock_open(addrinfo, SOCKOPEN_CLIENT, 0,
2127c2630c9philip		    errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
2128c2630c9philip		{
2129c2630c9philip			freeaddrinfo(addrinfo);
2130c2630c9philip			return -1;
2131c2630c9philip		}
2132c2630c9philip
2133c2630c9philip		/* addrinfo is no longer used */
2134c2630c9philip		freeaddrinfo(addrinfo);
2135c2630c9philip		addrinfo = NULL;
2136c2630c9philip
2137c2630c9philip		if (rpcap_doauth(*sockctrlp, protocol_versionp, auth,
2138c2630c9philip		    errbuf) == -1)
2139c2630c9philip		{
2140c2630c9philip			sock_close(*sockctrlp, NULL, 0);
2141c2630c9philip			return -1;
2142c2630c9philip		}
2143c2630c9philip	}
2144c2630c9philip	return 0;
2145c2630c9philip}
2146c2630c9philip
214719bb0b8hselasky/*
214819bb0b8hselasky * This function opens a remote adapter by opening an RPCAP connection and
214919bb0b8hselasky * so on.
215094960e5delphij *
215119bb0b8hselasky * It does the job of pcap_open_live() for a remote interface; it's called
215219bb0b8hselasky * by pcap_open() for remote interfaces.
215394960e5delphij *
215419bb0b8hselasky * We do not start the capture until pcap_startcapture_remote() is called.
215594960e5delphij *
215619bb0b8hselasky * This is because, when doing a remote capture, we cannot start capturing
215719bb0b8hselasky * data as soon as the 'open adapter' command is sent. Suppose the remote
215819bb0b8hselasky * adapter is already overloaded; if we start a capture (which, by default,
215919bb0b8hselasky * has a NULL filter) the new traffic can saturate the network.
216094960e5delphij *
216119bb0b8hselasky * Instead, we want to "open" the adapter, then send a "start capture"
216219bb0b8hselasky * command only when we're ready to start the capture.
216319bb0b8hselasky * This function does this job: it sends an "open adapter" command
216419bb0b8hselasky * (according to the RPCAP protocol), but it does not start the capture.
216594960e5delphij *
216619bb0b8hselasky * Since the other libpcap functions do not share this way of life, we
216719bb0b8hselasky * have to do some dirty things in order to make everything work.
216894960e5delphij *
216919bb0b8hselasky * \param source: see pcap_open().
217019bb0b8hselasky * \param snaplen: see pcap_open().
217119bb0b8hselasky * \param flags: see pcap_open().
217219bb0b8hselasky * \param read_timeout: see pcap_open().
217319bb0b8hselasky * \param auth: see pcap_open().
217419bb0b8hselasky * \param errbuf: see pcap_open().
217594960e5delphij *
217619bb0b8hselasky * \return a pcap_t pointer in case of success, NULL otherwise. In case of
217719bb0b8hselasky * success, the pcap_t pointer can be used as a parameter to the following
217819bb0b8hselasky * calls (pcap_compile() and so on). In case of problems, errbuf contains
217919bb0b8hselasky * a text explanation of error.
218094960e5delphij *
218119bb0b8hselasky * WARNING: In case we call pcap_compile() and the capture has not yet
218219bb0b8hselasky * been started, the filter will be saved into the pcap_t structure,
218319bb0b8hselasky * and it will be sent to the other host later (when
218419bb0b8hselasky * pcap_startcapture_remote() is called).
218594960e5delphij */
218619bb0b8hselaskypcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)
218794960e5delphij{
218819bb0b8hselasky	pcap_t *fp;
218919bb0b8hselasky	char *source_str;
219019bb0b8hselasky	struct pcap_rpcap *pr;		/* structure used when doing a remote live capture */
219119bb0b8hselasky	char host[PCAP_BUF_SIZE], ctrlport[PCAP_BUF_SIZE], iface[PCAP_BUF_SIZE];
219219bb0b8hselasky	SOCKET sockctrl;
219319bb0b8hselasky	uint8 protocol_version;			/* negotiated protocol version */
219419bb0b8hselasky	int active;
219519bb0b8hselasky	uint32 plen;
219619bb0b8hselasky	char sendbuf[RPCAP_NETBUF_SIZE];	/* temporary buffer in which data to be sent is buffered */
219719bb0b8hselasky	int sendbufidx = 0;			/* index which keeps the number of bytes currently buffered */
219894960e5delphij
219919bb0b8hselasky	/* RPCAP-related variables */
220019bb0b8hselasky	struct rpcap_header header;		/* header of the RPCAP packet */
220119bb0b8hselasky	struct rpcap_openreply openreply;	/* open reply message */
220294960e5delphij
220319bb0b8hselasky	fp = pcap_create_common(errbuf, sizeof (struct pcap_rpcap));
220419bb0b8hselasky	if (fp == NULL)
220594960e5delphij	{
220619bb0b8hselasky		return NULL;
220719bb0b8hselasky	}
220819bb0b8hselasky	source_str = strdup(source);
220919bb0b8hselasky	if (source_str == NULL) {
221019bb0b8hselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
221119bb0b8hselasky		    errno, "malloc");
221219bb0b8hselasky		return NULL;
221319bb0b8hselasky	}
221494960e5delphij
221519bb0b8hselasky	/*
221619bb0b8hselasky	 * Turn a negative snapshot value (invalid), a snapshot value of
221719bb0b8hselasky	 * 0 (unspecified), or a value bigger than the normal maximum
221819bb0b8hselasky	 * value, into the maximum allowed value.
221919bb0b8hselasky	 *
222019bb0b8hselasky	 * If some application really *needs* a bigger snapshot
222119bb0b8hselasky	 * length, we should just increase MAXIMUM_SNAPLEN.
222219bb0b8hselasky	 *
222319bb0b8hselasky	 * XXX - should we leave this up to the remote server to
222419bb0b8hselasky	 * do?
222519bb0b8hselasky	 */
222619bb0b8hselasky	if (snaplen <= 0 || snaplen > MAXIMUM_SNAPLEN)
222719bb0b8hselasky		snaplen = MAXIMUM_SNAPLEN;
222819bb0b8hselasky
222919bb0b8hselasky	fp->opt.device = source_str;
223019bb0b8hselasky	fp->snapshot = snaplen;
223119bb0b8hselasky	fp->opt.timeout = read_timeout;
223219bb0b8hselasky	pr = fp->priv;
223319bb0b8hselasky	pr->rmt_flags = flags;
223419bb0b8hselasky
223519bb0b8hselasky	/*
2236c2630c9philip	 * Attempt to set up the session with the server.
223719bb0b8hselasky	 */
2238c2630c9philip	if (rpcap_setup_session(fp->opt.device, auth, &active, &sockctrl,
2239c2630c9philip	    &protocol_version, host, ctrlport, iface, errbuf) == -1)
224019bb0b8hselasky	{
2241c2630c9philip		/* Session setup failed. */
224219bb0b8hselasky		pcap_close(fp);
224319bb0b8hselasky		return NULL;
224494960e5delphij	}
224594960e5delphij
224619bb0b8hselasky	/*
224719bb0b8hselasky	 * Now it's time to start playing with the RPCAP protocol
224819bb0b8hselasky	 * RPCAP open command: create the request message
224919bb0b8hselasky	 */
225019bb0b8hselasky	if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
225119bb0b8hselasky		&sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE))
225219bb0b8hselasky		goto error_nodiscard;
225319bb0b8hselasky
225419bb0b8hselasky	rpcap_createhdr((struct rpcap_header *) sendbuf, protocol_version,
225519bb0b8hselasky	    RPCAP_MSG_OPEN_REQ, 0, (uint32) strlen(iface));
225694960e5delphij
225719bb0b8hselasky	if (sock_bufferize(iface, (int) strlen(iface), sendbuf, &sendbufidx,
225819bb0b8hselasky		RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE))
225919bb0b8hselasky		goto error_nodiscard;
226094960e5delphij
226119bb0b8hselasky	if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf,
226219bb0b8hselasky	    PCAP_ERRBUF_SIZE) < 0)
226319bb0b8hselasky		goto error_nodiscard;
226494960e5delphij
226519bb0b8hselasky	/* Receive and process the reply message header. */
226619bb0b8hselasky	if (rpcap_process_msg_header(sockctrl, protocol_version,
226719bb0b8hselasky	    RPCAP_MSG_OPEN_REQ, &header, errbuf) == -1)
226819bb0b8hselasky		goto error_nodiscard;
226919bb0b8hselasky	plen = header.plen;
227019bb0b8hselasky
227119bb0b8hselasky	/* Read the reply body */
227219bb0b8hselasky	if (rpcap_recv(sockctrl, (char *)&openreply,
227319bb0b8hselasky	    sizeof(struct rpcap_openreply), &plen, errbuf) == -1)
227419bb0b8hselasky		goto error;
227519bb0b8hselasky
227619bb0b8hselasky	/* Discard the rest of the message, if there is any. */
2277c2630c9philip	if (rpcap_discard(sockctrl, plen, errbuf) == -1)
227819bb0b8hselasky		goto error_nodiscard;
227919bb0b8hselasky
228019bb0b8hselasky	/* Set proper fields into the pcap_t struct */
228119bb0b8hselasky	fp->linktype = ntohl(openreply.linktype);
228219bb0b8hselasky	fp->tzoff = ntohl(openreply.tzoff);
228319bb0b8hselasky	pr->rmt_sockctrl = sockctrl;
228419bb0b8hselasky	pr->protocol_version = protocol_version;
228519bb0b8hselasky	pr->rmt_clientside = 1;
228619bb0b8hselasky
228719bb0b8hselasky	/* This code is duplicated from the end of this function */
228819bb0b8hselasky	fp->read_op = pcap_read_rpcap;
228919bb0b8hselasky	fp->save_current_filter_op = pcap_save_current_filter_rpcap;
229019bb0b8hselasky	fp->setfilter_op = pcap_setfilter_rpcap;
229119bb0b8hselasky	fp->getnonblock_op = pcap_getnonblock_rpcap;
229219bb0b8hselasky	fp->setnonblock_op = pcap_setnonblock_rpcap;
229319bb0b8hselasky	fp->stats_op = pcap_stats_rpcap;
229419bb0b8hselasky#ifdef _WIN32
229519bb0b8hselasky	fp->stats_ex_op = pcap_stats_ex_rpcap;
229619bb0b8hselasky#endif
229719bb0b8hselasky	fp->cleanup_op = pcap_cleanup_rpcap;
229819bb0b8hselasky
229919bb0b8hselasky	fp->activated = 1;
230019bb0b8hselasky	return fp;
230119bb0b8hselasky
230219bb0b8hselaskyerror:
230394960e5delphij	/*
230419bb0b8hselasky	 * When the connection has been established, we have to close it. So, at the
230519bb0b8hselasky	 * beginning of this function, if an error occur we return immediately with
230619bb0b8hselasky	 * a return NULL; when the connection is established, we have to come here
230719bb0b8hselasky	 * ('goto error;') in order to close everything properly.
230894960e5delphij	 */
230994960e5delphij
231019bb0b8hselasky	/*
231119bb0b8hselasky	 * Discard the rest of the message.
231219bb0b8hselasky	 * We already reported an error; if this gets an error, just
231319bb0b8hselasky	 * drive on.
231419bb0b8hselasky	 */
2315c2630c9philip	(void)rpcap_discard(sockctrl, plen, NULL);
231694960e5delphij
231719bb0b8hselaskyerror_nodiscard:
231819bb0b8hselasky	if (!active)
231919bb0b8hselasky		sock_close(sockctrl, NULL, 0);
232094960e5delphij
232119bb0b8hselasky	pcap_close(fp);
232219bb0b8hselasky	return NULL;
232394960e5delphij}
232494960e5delphij
232519bb0b8hselasky/* String identifier to be used in the pcap_findalldevs_ex() */
232619bb0b8hselasky#define PCAP_TEXT_SOURCE_ADAPTER "Network adapter"
2327c2630c9philip#define PCAP_TEXT_SOURCE_ADAPTER_LEN (sizeof PCAP_TEXT_SOURCE_ADAPTER - 1)
232819bb0b8hselasky/* String identifier to be used in the pcap_findalldevs_ex() */
232919bb0b8hselasky#define PCAP_TEXT_SOURCE_ON_REMOTE_HOST "on remote node"
2330c2630c9philip#define PCAP_TEXT_SOURCE_ON_REMOTE_HOST_LEN (sizeof PCAP_TEXT_SOURCE_ON_REMOTE_HOST - 1)
233119bb0b8hselasky
233219bb0b8hselaskystatic void
233319bb0b8hselaskyfreeaddr(struct pcap_addr *addr)
233494960e5delphij{
233519bb0b8hselasky	free(addr->addr);
233619bb0b8hselasky	free(addr->netmask);
233719bb0b8hselasky	free(addr->broadaddr);
233819bb0b8hselasky	free(addr->dstaddr);
233919bb0b8hselasky	free(addr);
234019bb0b8hselasky}
234194960e5delphij
234219bb0b8hselaskyint
2343c2630c9philippcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
234419bb0b8hselasky{
234519bb0b8hselasky	uint8 protocol_version;		/* protocol version */
234619bb0b8hselasky	SOCKET sockctrl;		/* socket descriptor of the control connection */
234719bb0b8hselasky	uint32 plen;
234819bb0b8hselasky	struct rpcap_header header;	/* structure that keeps the general header of the rpcap protocol */
234919bb0b8hselasky	int i, j;		/* temp variables */
235019bb0b8hselasky	int nif;		/* Number of interfaces listed */
235119bb0b8hselasky	int active;			/* 'true' if we the other end-party is in active mode */
235219bb0b8hselasky	char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE];
235319bb0b8hselasky	char tmpstring[PCAP_BUF_SIZE + 1];		/* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
235419bb0b8hselasky	pcap_if_t *lastdev;	/* Last device in the pcap_if_t list */
235519bb0b8hselasky	pcap_if_t *dev;		/* Device we're adding to the pcap_if_t list */
235619bb0b8hselasky
235719bb0b8hselasky	/* List starts out empty. */
235819bb0b8hselasky	(*alldevs) = NULL;
235919bb0b8hselasky	lastdev = NULL;
236019bb0b8hselasky
2361c2630c9philip	/*
2362c2630c9philip	 * Attempt to set up the session with the server.
2363c2630c9philip	 */
2364c2630c9philip	if (rpcap_setup_session(source, auth, &active, &sockctrl,
2365c2630c9philip	    &protocol_version, host, port, NULL, errbuf) == -1)
236619bb0b8hselasky	{
2367c2630c9philip		/* Session setup failed. */
2368c2630c9philip		return -1;
236919bb0b8hselasky	}
237019bb0b8hselasky
237119bb0b8hselasky	/* RPCAP findalldevs command */
237219bb0b8hselasky	rpcap_createhdr(&header, protocol_version, RPCAP_MSG_FINDALLIF_REQ,
237319bb0b8hselasky	    0, 0);
237419bb0b8hselasky
237519bb0b8hselasky	if (sock_send(sockctrl, (char *)&header, sizeof(struct rpcap_header),
237619bb0b8hselasky	    errbuf, PCAP_ERRBUF_SIZE) < 0)
237719bb0b8hselasky		goto error_nodiscard;
237819bb0b8hselasky
237919bb0b8hselasky	/* Receive and process the reply message header. */
238019bb0b8hselasky	if (rpcap_process_msg_header(sockctrl, protocol_version,
238119bb0b8hselasky	    RPCAP_MSG_FINDALLIF_REQ, &header, errbuf) == -1)
238219bb0b8hselasky		goto error_nodiscard;
238319bb0b8hselasky
238419bb0b8hselasky	plen = header.plen;
238519bb0b8hselasky
238619bb0b8hselasky	/* read the number of interfaces */
238719bb0b8hselasky	nif = ntohs(header.value);
238819bb0b8hselasky
238919bb0b8hselasky	/* loop until all interfaces have been received */
239019bb0b8hselasky	for (i = 0; i < nif; i++)
239119bb0b8hselasky	{
239219bb0b8hselasky		struct rpcap_findalldevs_if findalldevs_if;
239319bb0b8hselasky		char tmpstring2[PCAP_BUF_SIZE + 1];		/* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
239419bb0b8hselasky		struct pcap_addr *addr, *prevaddr;
239519bb0b8hselasky
239619bb0b8hselasky		tmpstring2[PCAP_BUF_SIZE] = 0;
239719bb0b8hselasky
239819bb0b8hselasky		/* receive the findalldevs structure from remote host */
239919bb0b8hselasky		if (rpcap_recv(sockctrl, (char *)&findalldevs_if,
240019bb0b8hselasky		    sizeof(struct rpcap_findalldevs_if), &plen, errbuf) == -1)
240119bb0b8hselasky			goto error;
240219bb0b8hselasky
240319bb0b8hselasky		findalldevs_if.namelen = ntohs(findalldevs_if.namelen);
240419bb0b8hselasky		findalldevs_if.desclen = ntohs(findalldevs_if.desclen);
240519bb0b8hselasky		findalldevs_if.naddr = ntohs(findalldevs_if.naddr);
240619bb0b8hselasky
240719bb0b8hselasky		/* allocate the main structure */
240819bb0b8hselasky		dev = (pcap_if_t *)malloc(sizeof(pcap_if_t));
240919bb0b8hselasky		if (dev == NULL)
241019bb0b8hselasky		{
241119bb0b8hselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
241219bb0b8hselasky			    errno, "malloc() failed");
241319bb0b8hselasky			goto error;
241419bb0b8hselasky		}
241519bb0b8hselasky
241619bb0b8hselasky		/* Initialize the structure to 'zero' */
241719bb0b8hselasky		memset(dev, 0, sizeof(pcap_if_t));
241819bb0b8hselasky
241919bb0b8hselasky		/* Append it to the list. */
242019bb0b8hselasky		if (lastdev == NULL)
242119bb0b8hselasky		{
242219bb0b8hselasky			/*
242319bb0b8hselasky			 * List is empty, so it's also the first device.
242419bb0b8hselasky			 */
242519bb0b8hselasky			*alldevs = dev;
242619bb0b8hselasky		}
242719bb0b8hselasky		else
242819bb0b8hselasky		{
242919bb0b8hselasky			/*
243019bb0b8hselasky			 * Append after the last device.
243119bb0b8hselasky			 */
243219bb0b8hselasky			lastdev->next = dev;
243319bb0b8hselasky		}
243419bb0b8hselasky		/* It's now the last device. */
243519bb0b8hselasky		lastdev = dev;
243619bb0b8hselasky
243719bb0b8hselasky		/* allocate mem for name and description */
243819bb0b8hselasky		if (findalldevs_if.namelen)
243919bb0b8hselasky		{
244019bb0b8hselasky
244119bb0b8hselasky			if (findalldevs_if.namelen >= sizeof(tmpstring))
244219bb0b8hselasky			{
244319bb0b8hselasky				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface name too long");
244419bb0b8hselasky				goto error;
244519bb0b8hselasky			}
244619bb0b8hselasky
244719bb0b8hselasky			/* Retrieve adapter name */
244819bb0b8hselasky			if (rpcap_recv(sockctrl, tmpstring,
244919bb0b8hselasky			    findalldevs_if.namelen, &plen, errbuf) == -1)
245019bb0b8hselasky				goto error;
245119bb0b8hselasky
245219bb0b8hselasky			tmpstring[findalldevs_if.namelen] = 0;
245319bb0b8hselasky
245419bb0b8hselasky			/* Create the new device identifier */
2455c2630c9philip			if (pcap_createsrcstr(tmpstring2, PCAP_SRC_IFREMOTE,
2456c2630c9philip			    host, port, tmpstring, errbuf) == -1)
2457c2630c9philip				goto error;
245819bb0b8hselasky
2459c2630c9philip			dev->name = strdup(tmpstring2);
246019bb0b8hselasky			if (dev->name == NULL)
246119bb0b8hselasky			{
246219bb0b8hselasky				pcap_fmt_errmsg_for_errno(errbuf,
246319bb0b8hselasky				    PCAP_ERRBUF_SIZE, errno, "malloc() failed");
246419bb0b8hselasky				goto error;
246519bb0b8hselasky			}
246619bb0b8hselasky		}
246719bb0b8hselasky
246819bb0b8hselasky		if (findalldevs_if.desclen)
246919bb0b8hselasky		{
247019bb0b8hselasky			if (findalldevs_if.desclen >= sizeof(tmpstring))
247119bb0b8hselasky			{
247219bb0b8hselasky				pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface description too long");
247319bb0b8hselasky				goto error;
247419bb0b8hselasky			}
247519bb0b8hselasky
247619bb0b8hselasky			/* Retrieve adapter description */
247719bb0b8hselasky			if (rpcap_recv(sockctrl, tmpstring,
247819bb0b8hselasky			    findalldevs_if.desclen, &plen, errbuf) == -1)
247919bb0b8hselasky				goto error;
248019bb0b8hselasky
248119bb0b8hselasky			tmpstring[findalldevs_if.desclen] = 0;
248219bb0b8hselasky
2483c2630c9philip			if (pcap_asprintf(&dev->description,
2484c2630c9philip			    "%s '%s' %s %s", PCAP_TEXT_SOURCE_ADAPTER,
2485c2630c9philip			    tmpstring, PCAP_TEXT_SOURCE_ON_REMOTE_HOST, host) == -1)
248619bb0b8hselasky			{
248719bb0b8hselasky				pcap_fmt_errmsg_for_errno(errbuf,
248819bb0b8hselasky				    PCAP_ERRBUF_SIZE, errno, "malloc() failed");
248919bb0b8hselasky				goto error;
249019bb0b8hselasky			}
249119bb0b8hselasky		}
249219bb0b8hselasky
249319bb0b8hselasky		dev->flags = ntohl(findalldevs_if.flags);
249419bb0b8hselasky
249519bb0b8hselasky		prevaddr = NULL;
249619bb0b8hselasky		/* loop until all addresses have been received */
249719bb0b8hselasky		for (j = 0; j < findalldevs_if.naddr; j++)
249819bb0b8hselasky		{
249919bb0b8hselasky			struct rpcap_findalldevs_ifaddr ifaddr;
250019bb0b8hselasky
250119bb0b8hselasky			/* Retrieve the interface addresses */
250219bb0b8hselasky			if (rpcap_recv(sockctrl, (char *)&ifaddr,
250319bb0b8hselasky			    sizeof(struct rpcap_findalldevs_ifaddr),
250419bb0b8hselasky			    &plen, errbuf) == -1)
250519bb0b8hselasky				goto error;
250619bb0b8hselasky
250719bb0b8hselasky			/*
250819bb0b8hselasky			 * Deserialize all the address components.
250919bb0b8hselasky			 */
251019bb0b8hselasky			addr = (struct pcap_addr *) malloc(sizeof(struct pcap_addr));
251119bb0b8hselasky			if (addr == NULL)
251219bb0b8hselasky			{
251319bb0b8hselasky				pcap_fmt_errmsg_for_errno(errbuf,
251419bb0b8hselasky				    PCAP_ERRBUF_SIZE, errno, "malloc() failed");
251519bb0b8hselasky				goto error;
251619bb0b8hselasky			}
251719bb0b8hselasky			addr->next = NULL;
251819bb0b8hselasky			addr->addr = NULL;
251919bb0b8hselasky			addr->netmask = NULL;
252019bb0b8hselasky			addr->broadaddr = NULL;
252119bb0b8hselasky			addr->dstaddr = NULL;
252219bb0b8hselasky
252319bb0b8hselasky			if (rpcap_deseraddr(&ifaddr.addr,
252419bb0b8hselasky				(struct sockaddr_storage **) &addr->addr, errbuf) == -1)
252519bb0b8hselasky			{
252619bb0b8hselasky				freeaddr(addr);
252719bb0b8hselasky				goto error;
252819bb0b8hselasky			}
252919bb0b8hselasky			if (rpcap_deseraddr(&ifaddr.netmask,
253019bb0b8hselasky				(struct sockaddr_storage **) &addr->netmask, errbuf) == -1)
253119bb0b8hselasky			{
253219bb0b8hselasky				freeaddr(addr);
253319bb0b8hselasky				goto error;
253419bb0b8hselasky			}
253519bb0b8hselasky			if (rpcap_deseraddr(&ifaddr.broadaddr,
253619bb0b8hselasky				(struct sockaddr_storage **) &addr->broadaddr, errbuf) == -1)
253719bb0b8hselasky			{
253819bb0b8hselasky				freeaddr(addr);
253919bb0b8hselasky				goto error;
254019bb0b8hselasky			}
254119bb0b8hselasky			if (rpcap_deseraddr(&ifaddr.dstaddr,
254219bb0b8hselasky				(struct sockaddr_storage **) &addr->dstaddr, errbuf) == -1)
254319bb0b8hselasky			{
254419bb0b8hselasky				freeaddr(addr);
254519bb0b8hselasky				goto error;
254619bb0b8hselasky			}
254719bb0b8hselasky
254819bb0b8hselasky			if ((addr->addr == NULL) && (addr->netmask == NULL) &&
254919bb0b8hselasky				(addr->broadaddr == NULL) && (addr->dstaddr == NULL))
255019bb0b8hselasky			{
255119bb0b8hselasky				/*
255219bb0b8hselasky				 * None of the addresses are IPv4 or IPv6
255319bb0b8hselasky				 * addresses, so throw this entry away.
255419bb0b8hselasky				 */
255519bb0b8hselasky				free(addr);
255619bb0b8hselasky			}
255719bb0b8hselasky			else
255819bb0b8hselasky			{
255919bb0b8hselasky				/*
256019bb0b8hselasky				 * Add this entry to the list.
256119bb0b8hselasky				 */
256219bb0b8hselasky				if (prevaddr == NULL)
256319bb0b8hselasky				{
256419bb0b8hselasky					dev->addresses = addr;
256519bb0b8hselasky				}
256619bb0b8hselasky				else
256719bb0b8hselasky				{
256819bb0b8hselasky					prevaddr->next = addr;
256919bb0b8hselasky				}
257019bb0b8hselasky				prevaddr = addr;
257119bb0b8hselasky			}
257219bb0b8hselasky		}
257319bb0b8hselasky	}
257419bb0b8hselasky
257519bb0b8hselasky	/* Discard the rest of the message. */
257619bb0b8hselasky	if (rpcap_discard(sockctrl, plen, errbuf) == 1)
2577c2630c9philip		goto error_nodiscard;
257819bb0b8hselasky
257919bb0b8hselasky	/* Control connection has to be closed only in case the remote machine is in passive mode */
258019bb0b8hselasky	if (!active)
258119bb0b8hselasky	{
258219bb0b8hselasky		/* DO not send RPCAP_CLOSE, since we did not open a pcap_t; no need to free resources */
258319bb0b8hselasky		if (sock_close(sockctrl, errbuf, PCAP_ERRBUF_SIZE))
258419bb0b8hselasky			return -1;
258519bb0b8hselasky	}
258619bb0b8hselasky
258719bb0b8hselasky	/* To avoid inconsistencies in the number of sock_init() */
258819bb0b8hselasky	sock_cleanup();
258919bb0b8hselasky
259019bb0b8hselasky	return 0;
259119bb0b8hselasky
259219bb0b8hselaskyerror:
259319bb0b8hselasky	/*
259419bb0b8hselasky	 * In case there has been an error, I don't want to overwrite it with a new one
259519bb0b8hselasky	 * if the following call fails. I want to return always the original error.
259619bb0b8hselasky	 *
259719bb0b8hselasky	 * Take care: this connection can already be closed when we try to close it.
259819bb0b8hselasky	 * This happens because a previous error in the rpcapd, which requested to
259919bb0b8hselasky	 * closed the connection. In that case, we already recognized that into the
260019bb0b8hselasky	 * rpspck_isheaderok() and we already acknowledged the closing.
260119bb0b8hselasky	 * In that sense, this call is useless here (however it is needed in case
260219bb0b8hselasky	 * the client generates the error).
260319bb0b8hselasky	 *
260419bb0b8hselasky	 * Checks if all the data has been read; if not, discard the data in excess
260594960e5delphij	 */
260619bb0b8hselasky	(void) rpcap_discard(sockctrl, plen, NULL);
260719bb0b8hselasky
260819bb0b8hselaskyerror_nodiscard:
260919bb0b8hselasky	/* Control connection has to be closed only in case the remote machine is in passive mode */
261019bb0b8hselasky	if (!active)
261119bb0b8hselasky		sock_close(sockctrl, NULL, 0);
261219bb0b8hselasky
261319bb0b8hselasky	/* To avoid inconsistencies in the number of sock_init() */
261419bb0b8hselasky	sock_cleanup();
261519bb0b8hselasky
261619bb0b8hselasky	/* Free whatever interfaces we've allocated. */
261719bb0b8hselasky	pcap_freealldevs(*alldevs);
261819bb0b8hselasky
261919bb0b8hselasky	return -1;
262019bb0b8hselasky}
262119bb0b8hselasky
262219bb0b8hselasky/*
262319bb0b8hselasky * Active mode routines.
262419bb0b8hselasky *
262519bb0b8hselasky * The old libpcap API is somewhat ugly, and makes active mode difficult
262619bb0b8hselasky * to implement; we provide some APIs for it that work only with rpcap.
262719bb0b8hselasky */
262819bb0b8hselasky
262919bb0b8hselaskySOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf)
263019bb0b8hselasky{
263119bb0b8hselasky	/* socket-related variables */
263219bb0b8hselasky	struct addrinfo hints;			/* temporary struct to keep settings needed to open the new socket */
263319bb0b8hselasky	struct addrinfo *addrinfo;		/* keeps the addrinfo chain; required to open a new socket */
263419bb0b8hselasky	struct sockaddr_storage from;	/* generic sockaddr_storage variable */
263519bb0b8hselasky	socklen_t fromlen;				/* keeps the length of the sockaddr_storage variable */
263619bb0b8hselasky	SOCKET sockctrl;				/* keeps the main socket identifier */
263719bb0b8hselasky	uint8 protocol_version;			/* negotiated protocol version */
263819bb0b8hselasky	struct activehosts *temp, *prev;	/* temp var needed to scan he host list chain */
263919bb0b8hselasky
264019bb0b8hselasky	*connectinghost = 0;		/* just in case */
264119bb0b8hselasky
264219bb0b8hselasky	/* Prepare to open a new server socket */
264319bb0b8hselasky	memset(&hints, 0, sizeof(struct addrinfo));
264419bb0b8hselasky	/* WARNING Currently it supports only ONE socket family among ipv4 and IPv6  */
264519bb0b8hselasky	hints.ai_family = AF_INET;		/* PF_UNSPEC to have both IPv4 and IPv6 server */
264619bb0b8hselasky	hints.ai_flags = AI_PASSIVE;	/* Ready to a bind() socket */
264719bb0b8hselasky	hints.ai_socktype = SOCK_STREAM;
264819bb0b8hselasky
264919bb0b8hselasky	/* Warning: this call can be the first one called by the user. */
265019bb0b8hselasky	/* For this reason, we have to initialize the WinSock support. */
265119bb0b8hselasky	if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
265219bb0b8hselasky		return (SOCKET)-1;
265319bb0b8hselasky
265419bb0b8hselasky	/* Do the work */
265519bb0b8hselasky	if ((port == NULL) || (port[0] == 0))
265619bb0b8hselasky	{
265719bb0b8hselasky		if (sock_initaddress(address, RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
265819bb0b8hselasky		{
265919bb0b8hselasky			return (SOCKET)-2;
266019bb0b8hselasky		}
266119bb0b8hselasky	}
266219bb0b8hselasky	else
266319bb0b8hselasky	{
266419bb0b8hselasky		if (sock_initaddress(address, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
266519bb0b8hselasky		{
266619bb0b8hselasky			return (SOCKET)-2;
266719bb0b8hselasky		}
266819bb0b8hselasky	}
266919bb0b8hselasky
267019bb0b8hselasky
267119bb0b8hselasky	if ((sockmain = sock_open(addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
267219bb0b8hselasky	{
267319bb0b8hselasky		freeaddrinfo(addrinfo);
267419bb0b8hselasky		return (SOCKET)-2;
267519bb0b8hselasky	}
267619bb0b8hselasky	freeaddrinfo(addrinfo);
267719bb0b8hselasky
267819bb0b8hselasky	/* Connection creation */
267919bb0b8hselasky	fromlen = sizeof(struct sockaddr_storage);
268019bb0b8hselasky
268119bb0b8hselasky	sockctrl = accept(sockmain, (struct sockaddr *) &from, &fromlen);
268219bb0b8hselasky
268319bb0b8hselasky	/* We're not using sock_close, since we do not want to send a shutdown */
268419bb0b8hselasky	/* (which is not allowed on a non-connected socket) */
268519bb0b8hselasky	closesocket(sockmain);
268619bb0b8hselasky	sockmain = 0;
268719bb0b8hselasky
268819bb0b8hselasky	if (sockctrl == INVALID_SOCKET)
268919bb0b8hselasky	{
2690c2630c9philip		sock_geterror("accept()", errbuf, PCAP_ERRBUF_SIZE);
269119bb0b8hselasky		return (SOCKET)-2;
269219bb0b8hselasky	}
269319bb0b8hselasky
269419bb0b8hselasky	/* Get the numeric for of the name of the connecting host */
269519bb0b8hselasky	if (getnameinfo((struct sockaddr *) &from, fromlen, connectinghost, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST))
269619bb0b8hselasky	{
2697c2630c9philip		sock_geterror("getnameinfo()", errbuf, PCAP_ERRBUF_SIZE);
269819bb0b8hselasky		rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
269919bb0b8hselasky		sock_close(sockctrl, NULL, 0);
270019bb0b8hselasky		return (SOCKET)-1;
270119bb0b8hselasky	}
270219bb0b8hselasky
270319bb0b8hselasky	/* checks if the connecting host is among the ones allowed */
270419bb0b8hselasky	if (sock_check_hostlist((char *)hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0)
270519bb0b8hselasky	{
270619bb0b8hselasky		rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
270719bb0b8hselasky		sock_close(sockctrl, NULL, 0);
270819bb0b8hselasky		return (SOCKET)-1;
270919bb0b8hselasky	}
271019bb0b8hselasky
271119bb0b8hselasky	/*
271219bb0b8hselasky	 * Send authentication to the remote machine.
271319bb0b8hselasky	 */
271419bb0b8hselasky	if (rpcap_doauth(sockctrl, &protocol_version, auth, errbuf) == -1)
271519bb0b8hselasky	{
271619bb0b8hselasky		/* Unrecoverable error. */
271719bb0b8hselasky		rpcap_senderror(sockctrl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
271819bb0b8hselasky		sock_close(sockctrl, NULL, 0);
271919bb0b8hselasky		return (SOCKET)-3;
272019bb0b8hselasky	}
272119bb0b8hselasky
272219bb0b8hselasky	/* Checks that this host does not already have a cntrl connection in place */
272319bb0b8hselasky
272419bb0b8hselasky	/* Initialize pointers */
272519bb0b8hselasky	temp = activeHosts;
272619bb0b8hselasky	prev = NULL;
272719bb0b8hselasky
272819bb0b8hselasky	while (temp)
272919bb0b8hselasky	{
273019bb0b8hselasky		/* This host already has an active connection in place, so I don't have to update the host list */
273119bb0b8hselasky		if (sock_cmpaddr(&temp->host, &from) == 0)
273219bb0b8hselasky			return sockctrl;
273319bb0b8hselasky
273419bb0b8hselasky		prev = temp;
273519bb0b8hselasky		temp = temp->next;
273619bb0b8hselasky	}
273719bb0b8hselasky
273819bb0b8hselasky	/* The host does not exist in the list; so I have to update the list */
273919bb0b8hselasky	if (prev)
274019bb0b8hselasky	{
274119bb0b8hselasky		prev->next = (struct activehosts *) malloc(sizeof(struct activehosts));
274219bb0b8hselasky		temp = prev->next;
274319bb0b8hselasky	}
274419bb0b8hselasky	else
274519bb0b8hselasky	{
274619bb0b8hselasky		activeHosts = (struct activehosts *) malloc(sizeof(struct activehosts));
274719bb0b8hselasky		temp = activeHosts;
274819bb0b8hselasky	}
274919bb0b8hselasky
275019bb0b8hselasky	if (temp == NULL)
275119bb0b8hselasky	{
275219bb0b8hselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
275319bb0b8hselasky		    errno, "malloc() failed");
275419bb0b8hselasky		rpcap_senderror(sockctrl, protocol_version, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
275519bb0b8hselasky		sock_close(sockctrl, NULL, 0);
275619bb0b8hselasky		return (SOCKET)-1;
275719bb0b8hselasky	}
275819bb0b8hselasky
275919bb0b8hselasky	memcpy(&temp->host, &from, fromlen);
276019bb0b8hselasky	temp->sockctrl = sockctrl;
276119bb0b8hselasky	temp->protocol_version = protocol_version;
276219bb0b8hselasky	temp->next = NULL;
276319bb0b8hselasky
276419bb0b8hselasky	return sockctrl;
276519bb0b8hselasky}
276619bb0b8hselasky
276719bb0b8hselaskyint pcap_remoteact_close(const char *host, char *errbuf)
276819bb0b8hselasky{
276919bb0b8hselasky	struct activehosts *temp, *prev;	/* temp var needed to scan the host list chain */
277019bb0b8hselasky	struct addrinfo hints, *addrinfo, *ai_next;	/* temp var needed to translate between hostname to its address */
277119bb0b8hselasky	int retval;
277219bb0b8hselasky
277319bb0b8hselasky	temp = activeHosts;
277419bb0b8hselasky	prev = NULL;
277519bb0b8hselasky
277619bb0b8hselasky	/* retrieve the network address corresponding to 'host' */
277719bb0b8hselasky	addrinfo = NULL;
277819bb0b8hselasky	memset(&hints, 0, sizeof(struct addrinfo));
277919bb0b8hselasky	hints.ai_family = PF_UNSPEC;
278019bb0b8hselasky	hints.ai_socktype = SOCK_STREAM;
278119bb0b8hselasky
278219bb0b8hselasky	retval = getaddrinfo(host, "0", &hints, &addrinfo);
278319bb0b8hselasky	if (retval != 0)
278419bb0b8hselasky	{
278519bb0b8hselasky		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval));
278619bb0b8hselasky		return -1;
278719bb0b8hselasky	}
278819bb0b8hselasky
278919bb0b8hselasky	while (temp)
279019bb0b8hselasky	{
279119bb0b8hselasky		ai_next = addrinfo;
279219bb0b8hselasky		while (ai_next)
279319bb0b8hselasky		{
279419bb0b8hselasky			if (sock_cmpaddr(&temp->host, (struct sockaddr_storage *) ai_next->ai_addr) == 0)
279519bb0b8hselasky			{
279619bb0b8hselasky				struct rpcap_header header;
279719bb0b8hselasky				int status = 0;
279819bb0b8hselasky
279919bb0b8hselasky				/* Close this connection */
280019bb0b8hselasky				rpcap_createhdr(&header, temp->protocol_version,
280119bb0b8hselasky				    RPCAP_MSG_CLOSE, 0, 0);
280219bb0b8hselasky
280319bb0b8hselasky				/*
280419bb0b8hselasky				 * Don't check for errors, since we're
280519bb0b8hselasky				 * just cleaning up.
280619bb0b8hselasky				 */
280719bb0b8hselasky				if (sock_send(temp->sockctrl,
280819bb0b8hselasky				    (char *)&header,
280919bb0b8hselasky				    sizeof(struct rpcap_header), errbuf,
281019bb0b8hselasky				    PCAP_ERRBUF_SIZE) < 0)
281119bb0b8hselasky				{
281219bb0b8hselasky					/*
281319bb0b8hselasky					 * Let that error be the one we
281419bb0b8hselasky					 * report.
281519bb0b8hselasky					 */
281619bb0b8hselasky					(void)sock_close(temp->sockctrl, NULL,
281719bb0b8hselasky					   0);
281819bb0b8hselasky					status = -1;
281919bb0b8hselasky				}
282019bb0b8hselasky				else
282119bb0b8hselasky				{
282219bb0b8hselasky					if (sock_close(temp->sockctrl, errbuf,
282319bb0b8hselasky					   PCAP_ERRBUF_SIZE) == -1)
282419bb0b8hselasky						status = -1;
282519bb0b8hselasky				}
282619bb0b8hselasky
282719bb0b8hselasky				/*
282819bb0b8hselasky				 * Remove the host from the list of active
282919bb0b8hselasky				 * hosts.
283019bb0b8hselasky				 */
283119bb0b8hselasky				if (prev)
283219bb0b8hselasky					prev->next = temp->next;
283319bb0b8hselasky				else
283419bb0b8hselasky					activeHosts = temp->next;
283519bb0b8hselasky
283619bb0b8hselasky				freeaddrinfo(addrinfo);
283719bb0b8hselasky
283819bb0b8hselasky				free(temp);
283919bb0b8hselasky
284019bb0b8hselasky				/* To avoid inconsistencies in the number of sock_init() */
284119bb0b8hselasky				sock_cleanup();
284219bb0b8hselasky
284319bb0b8hselasky				return status;
284419bb0b8hselasky			}
284519bb0b8hselasky
284619bb0b8hselasky			ai_next = ai_next->ai_next;
284719bb0b8hselasky		}
284819bb0b8hselasky		prev = temp;
284919bb0b8hselasky		temp = temp->next;
285019bb0b8hselasky	}
285119bb0b8hselasky
285219bb0b8hselasky	if (addrinfo)
285319bb0b8hselasky		freeaddrinfo(addrinfo);
285419bb0b8