1335640Shselasky/*
2335640Shselasky * Copyright (c) 2002 - 2003
3335640Shselasky * NetGroup, Politecnico di Torino (Italy)
4335640Shselasky * All rights reserved.
5335640Shselasky *
6335640Shselasky * Redistribution and use in source and binary forms, with or without
7335640Shselasky * modification, are permitted provided that the following conditions
8335640Shselasky * are met:
9335640Shselasky *
10335640Shselasky * 1. Redistributions of source code must retain the above copyright
11335640Shselasky * notice, this list of conditions and the following disclaimer.
12335640Shselasky * 2. Redistributions in binary form must reproduce the above copyright
13335640Shselasky * notice, this list of conditions and the following disclaimer in the
14335640Shselasky * documentation and/or other materials provided with the distribution.
15335640Shselasky * 3. Neither the name of the Politecnico di Torino nor the names of its
16335640Shselasky * contributors may be used to endorse or promote products derived from
17335640Shselasky * this software without specific prior written permission.
18335640Shselasky *
19335640Shselasky * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20335640Shselasky * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21335640Shselasky * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22335640Shselasky * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23335640Shselasky * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24335640Shselasky * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25335640Shselasky * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26335640Shselasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27335640Shselasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28335640Shselasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29335640Shselasky * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30335640Shselasky *
31335640Shselasky */
32335640Shselasky
33335640Shselasky#ifdef HAVE_CONFIG_H
34335640Shselasky#include <config.h>
35335640Shselasky#endif
36335640Shselasky
37335640Shselasky/*
38335640Shselasky * \file sockutils.c
39335640Shselasky *
40335640Shselasky * The goal of this file is to provide a common set of primitives for socket
41335640Shselasky * manipulation.
42335640Shselasky *
43335640Shselasky * Although the socket interface defined in the RFC 2553 (and its updates)
44335640Shselasky * is excellent, there are still differences between the behavior of those
45335640Shselasky * routines on UN*X and Windows, and between UN*Xes.
46335640Shselasky *
47335640Shselasky * These calls provide an interface similar to the socket interface, but
48335640Shselasky * that hides the differences between operating systems.  It does not
49335640Shselasky * attempt to significantly improve on the socket interface in other
50335640Shselasky * ways.
51335640Shselasky */
52335640Shselasky
53335640Shselasky#include "ftmacros.h"
54335640Shselasky
55335640Shselasky#include <string.h>
56335640Shselasky#include <errno.h>	/* for the errno variable */
57335640Shselasky#include <stdio.h>	/* for the stderr file */
58335640Shselasky#include <stdlib.h>	/* for malloc() and free() */
59335640Shselasky#ifdef HAVE_LIMITS_H
60335640Shselasky#include <limits.h>
61335640Shselasky#else
62335640Shselasky#define INT_MAX		2147483647
63335640Shselasky#endif
64335640Shselasky
65335640Shselasky#include "pcap-int.h"
66335640Shselasky
67335640Shselasky#include "sockutils.h"
68335640Shselasky#include "portability.h"
69335640Shselasky
70335640Shselasky#ifdef _WIN32
71335640Shselasky  /*
72335640Shselasky   * Winsock initialization.
73335640Shselasky   *
74335640Shselasky   * Ask for WinSock 2.2.
75335640Shselasky   */
76335640Shselasky  #define WINSOCK_MAJOR_VERSION 2
77335640Shselasky  #define WINSOCK_MINOR_VERSION 2
78335640Shselasky
79335640Shselasky  static int sockcount = 0;	/*!< Variable that allows calling the WSAStartup() only one time */
80335640Shselasky#endif
81335640Shselasky
82335640Shselasky/* Some minor differences between UNIX and Win32 */
83335640Shselasky#ifdef _WIN32
84335640Shselasky  #define SHUT_WR SD_SEND	/* The control code for shutdown() is different in Win32 */
85335640Shselasky#endif
86335640Shselasky
87335640Shselasky/* Size of the buffer that has to keep error messages */
88335640Shselasky#define SOCK_ERRBUF_SIZE 1024
89335640Shselasky
90335640Shselasky/* Constants; used in order to keep strings here */
91335640Shselasky#define SOCKET_NO_NAME_AVAILABLE "No name available"
92335640Shselasky#define SOCKET_NO_PORT_AVAILABLE "No port available"
93335640Shselasky#define SOCKET_NAME_NULL_DAD "Null address (possibly DAD Phase)"
94335640Shselasky
95335640Shselasky/*
96335640Shselasky * On UN*X, send() and recv() return ssize_t.
97335640Shselasky *
98335640Shselasky * On Windows, send() and recv() return an int.
99335640Shselasky *
100335640Shselasky *   Wth MSVC, there *is* no ssize_t.
101335640Shselasky *
102335640Shselasky *   With MinGW, there is an ssize_t type; it is either an int (32 bit)
103356341Scy *   or a long long (64 bit).
104335640Shselasky *
105335640Shselasky * So, on Windows, if we don't have ssize_t defined, define it as an
106335640Shselasky * int, so we can use it, on all platforms, as the type of variables
107335640Shselasky * that hold the return values from send() and recv().
108335640Shselasky */
109335640Shselasky#if defined(_WIN32) && !defined(_SSIZE_T_DEFINED)
110335640Shselaskytypedef int ssize_t;
111335640Shselasky#endif
112335640Shselasky
113335640Shselasky/****************************************************
114335640Shselasky *                                                  *
115335640Shselasky * Locally defined functions                        *
116335640Shselasky *                                                  *
117335640Shselasky ****************************************************/
118335640Shselasky
119335640Shselaskystatic int sock_ismcastaddr(const struct sockaddr *saddr);
120335640Shselasky
121335640Shselasky/****************************************************
122335640Shselasky *                                                  *
123335640Shselasky * Function bodies                                  *
124335640Shselasky *                                                  *
125335640Shselasky ****************************************************/
126335640Shselasky
127335640Shselasky/*
128335640Shselasky * Format an error message given an errno value (UN*X) or a WinSock error
129335640Shselasky * (Windows).
130335640Shselasky */
131335640Shselaskyvoid sock_fmterror(const char *caller, int errcode, char *errbuf, int errbuflen)
132335640Shselasky{
133335640Shselasky	if (errbuf == NULL)
134335640Shselasky		return;
135335640Shselasky
136356341Scy#ifdef _WIN32
137356341Scy	pcap_fmt_errmsg_for_win32_err(errbuf, errbuflen, errcode,
138356341Scy	    "%s", caller);
139335640Shselasky#else
140356341Scy	pcap_fmt_errmsg_for_errno(errbuf, errbuflen, errcode,
141356341Scy	    "%s", caller);
142335640Shselasky#endif
143335640Shselasky}
144335640Shselasky
145335640Shselasky/*
146335640Shselasky * \brief It retrieves the error message after an error occurred in the socket interface.
147335640Shselasky *
148335640Shselasky * This function is defined because of the different way errors are returned in UNIX
149335640Shselasky * and Win32. This function provides a consistent way to retrieve the error message
150335640Shselasky * (after a socket error occurred) on all the platforms.
151335640Shselasky *
152335640Shselasky * \param caller: a pointer to a user-allocated string which contains a message that has
153335640Shselasky * to be printed *before* the true error message. It could be, for example, 'this error
154356341Scy * comes from the recv() call at line 31'.
155335640Shselasky *
156335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
157335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
158335640Shselasky * It can be NULL; in this case the error cannot be printed.
159335640Shselasky *
160335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
161335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
162335640Shselasky *
163335640Shselasky * \return No return values. The error message is returned in the 'string' parameter.
164335640Shselasky */
165335640Shselaskyvoid sock_geterror(const char *caller, char *errbuf, int errbuflen)
166335640Shselasky{
167335640Shselasky#ifdef _WIN32
168335640Shselasky	sock_fmterror(caller, GetLastError(), errbuf, errbuflen);
169335640Shselasky#else
170335640Shselasky	sock_fmterror(caller, errno, errbuf, errbuflen);
171335640Shselasky#endif
172335640Shselasky}
173335640Shselasky
174335640Shselasky/*
175356341Scy * \brief This function initializes the socket mechanism if it hasn't
176356341Scy * already been initialized or reinitializes it after it has been
177356341Scy * cleaned up.
178335640Shselasky *
179356341Scy * On UN*Xes, it doesn't need to do anything; on Windows, it needs to
180356341Scy * initialize Winsock.
181335640Shselasky *
182356341Scy * \param errbuf: a pointer to an user-allocated buffer that will contain
183356341Scy * the complete error message. This buffer has to be at least 'errbuflen'
184356341Scy * in length. It can be NULL; in this case no error message is supplied.
185335640Shselasky *
186356341Scy * \param errbuflen: length of the buffer that will contains the error.
187356341Scy * The error message cannot be larger than 'errbuflen - 1' because the
188356341Scy * last char is reserved for the string terminator.
189335640Shselasky *
190356341Scy * \return '0' if everything is fine, '-1' if some errors occurred. The
191356341Scy * error message is returned in the buffer pointed to by 'errbuf' variable.
192335640Shselasky */
193335640Shselasky#ifdef _WIN32
194335640Shselaskyint sock_init(char *errbuf, int errbuflen)
195335640Shselasky{
196335640Shselasky	if (sockcount == 0)
197335640Shselasky	{
198335640Shselasky		WSADATA wsaData;			/* helper variable needed to initialize Winsock */
199335640Shselasky
200335640Shselasky		if (WSAStartup(MAKEWORD(WINSOCK_MAJOR_VERSION,
201335640Shselasky		    WINSOCK_MINOR_VERSION), &wsaData) != 0)
202335640Shselasky		{
203335640Shselasky			if (errbuf)
204335640Shselasky				pcap_snprintf(errbuf, errbuflen, "Failed to initialize Winsock\n");
205335640Shselasky
206335640Shselasky			WSACleanup();
207335640Shselasky
208335640Shselasky			return -1;
209335640Shselasky		}
210335640Shselasky	}
211335640Shselasky
212335640Shselasky	sockcount++;
213356341Scy	return 0;
214356341Scy}
215335640Shselasky#else
216335640Shselaskyint sock_init(char *errbuf _U_, int errbuflen _U_)
217335640Shselasky{
218356341Scy	/*
219356341Scy	 * Nothing to do on UN*Xes.
220356341Scy	 */
221335640Shselasky	return 0;
222335640Shselasky}
223356341Scy#endif
224335640Shselasky
225335640Shselasky/*
226356341Scy * \brief This function cleans up the socket mechanism if we have no
227356341Scy * sockets left open.
228335640Shselasky *
229356341Scy * On UN*Xes, it doesn't need to do anything; on Windows, it needs
230356341Scy * to clean up Winsock.
231335640Shselasky *
232335640Shselasky * \return No error values.
233335640Shselasky */
234335640Shselaskyvoid sock_cleanup(void)
235335640Shselasky{
236335640Shselasky#ifdef _WIN32
237335640Shselasky	sockcount--;
238335640Shselasky
239335640Shselasky	if (sockcount == 0)
240335640Shselasky		WSACleanup();
241335640Shselasky#endif
242335640Shselasky}
243335640Shselasky
244335640Shselasky/*
245335640Shselasky * \brief It checks if the sockaddr variable contains a multicast address.
246335640Shselasky *
247335640Shselasky * \return '0' if the address is multicast, '-1' if it is not.
248335640Shselasky */
249335640Shselaskystatic int sock_ismcastaddr(const struct sockaddr *saddr)
250335640Shselasky{
251335640Shselasky	if (saddr->sa_family == PF_INET)
252335640Shselasky	{
253335640Shselasky		struct sockaddr_in *saddr4 = (struct sockaddr_in *) saddr;
254335640Shselasky		if (IN_MULTICAST(ntohl(saddr4->sin_addr.s_addr))) return 0;
255335640Shselasky		else return -1;
256335640Shselasky	}
257335640Shselasky	else
258335640Shselasky	{
259335640Shselasky		struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) saddr;
260335640Shselasky		if (IN6_IS_ADDR_MULTICAST(&saddr6->sin6_addr)) return 0;
261335640Shselasky		else return -1;
262335640Shselasky	}
263335640Shselasky}
264335640Shselasky
265335640Shselasky/*
266335640Shselasky * \brief It initializes a network connection both from the client and the server side.
267335640Shselasky *
268335640Shselasky * In case of a client socket, this function calls socket() and connect().
269335640Shselasky * In the meanwhile, it checks for any socket error.
270335640Shselasky * If an error occurs, it writes the error message into 'errbuf'.
271335640Shselasky *
272335640Shselasky * In case of a server socket, the function calls socket(), bind() and listen().
273335640Shselasky *
274335640Shselasky * This function is usually preceeded by the sock_initaddress().
275335640Shselasky *
276335640Shselasky * \param addrinfo: pointer to an addrinfo variable which will be used to
277335640Shselasky * open the socket and such. This variable is the one returned by the previous call to
278335640Shselasky * sock_initaddress().
279335640Shselasky *
280335640Shselasky * \param server: '1' if this is a server socket, '0' otherwise.
281335640Shselasky *
282335640Shselasky * \param nconn: number of the connections that are allowed to wait into the listen() call.
283335640Shselasky * This value has no meanings in case of a client socket.
284335640Shselasky *
285335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
286335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
287335640Shselasky * It can be NULL; in this case the error cannot be printed.
288335640Shselasky *
289335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
290335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
291335640Shselasky *
292335640Shselasky * \return the socket that has been opened (that has to be used in the following sockets calls)
293335640Shselasky * if everything is fine, INVALID_SOCKET if some errors occurred. The error message is returned
294335640Shselasky * in the 'errbuf' variable.
295335640Shselasky */
296335640ShselaskySOCKET sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf, int errbuflen)
297335640Shselasky{
298335640Shselasky	SOCKET sock;
299335640Shselasky#if defined(SO_NOSIGPIPE) || defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY)
300335640Shselasky	int on = 1;
301335640Shselasky#endif
302335640Shselasky
303335640Shselasky	sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
304335640Shselasky	if (sock == INVALID_SOCKET)
305335640Shselasky	{
306356341Scy		sock_geterror("socket()", errbuf, errbuflen);
307335640Shselasky		return INVALID_SOCKET;
308335640Shselasky	}
309335640Shselasky
310335640Shselasky	/*
311335640Shselasky	 * Disable SIGPIPE, if we have SO_NOSIGPIPE.  We don't want to
312335640Shselasky	 * have to deal with signals if the peer closes the connection,
313335640Shselasky	 * especially in client programs, which may not even be aware that
314335640Shselasky	 * they're sending to sockets.
315335640Shselasky	 */
316335640Shselasky#ifdef SO_NOSIGPIPE
317335640Shselasky	if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (char *)&on,
318335640Shselasky	    sizeof (int)) == -1)
319335640Shselasky	{
320335640Shselasky		sock_geterror("setsockopt(SO_NOSIGPIPE)", errbuf, errbuflen);
321335640Shselasky		closesocket(sock);
322335640Shselasky		return INVALID_SOCKET;
323335640Shselasky	}
324335640Shselasky#endif
325335640Shselasky
326335640Shselasky	/* This is a server socket */
327335640Shselasky	if (server)
328335640Shselasky	{
329356341Scy		/*
330356341Scy		 * Allow a new server to bind the socket after the old one
331356341Scy		 * exited, even if lingering sockets are still present.
332356341Scy		 *
333356341Scy		 * Don't treat an error as a failure.
334356341Scy		 */
335356341Scy		int optval = 1;
336356341Scy		(void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
337356341Scy		    (char *)&optval, sizeof (optval));
338356341Scy
339335640Shselasky#if defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY)
340335640Shselasky		/*
341335640Shselasky		 * Force the use of IPv6-only addresses.
342335640Shselasky		 *
343335640Shselasky		 * RFC 3493 indicates that you can support IPv4 on an
344335640Shselasky		 * IPv6 socket:
345335640Shselasky		 *
346335640Shselasky		 *    https://tools.ietf.org/html/rfc3493#section-3.7
347335640Shselasky		 *
348335640Shselasky		 * and that this is the default behavior.  This means
349335640Shselasky		 * that if we first create an IPv6 socket bound to the
350335640Shselasky		 * "any" address, it is, in effect, also bound to the
351335640Shselasky		 * IPv4 "any" address, so when we create an IPv4 socket
352335640Shselasky		 * and try to bind it to the IPv4 "any" address, it gets
353335640Shselasky		 * EADDRINUSE.
354335640Shselasky		 *
355335640Shselasky		 * Not all network stacks support IPv4 on IPv6 sockets;
356335640Shselasky		 * pre-NT 6 Windows stacks don't support it, and the
357335640Shselasky		 * OpenBSD stack doesn't support it for security reasons
358335640Shselasky		 * (see the OpenBSD inet6(4) man page).  Therefore, we
359335640Shselasky		 * don't want to rely on this behavior.
360335640Shselasky		 *
361335640Shselasky		 * So we try to disable it, using either the IPV6_V6ONLY
362335640Shselasky		 * option from RFC 3493:
363335640Shselasky		 *
364335640Shselasky		 *    https://tools.ietf.org/html/rfc3493#section-5.3
365335640Shselasky		 *
366335640Shselasky		 * or the IPV6_BINDV6ONLY option from older UN*Xes.
367335640Shselasky		 */
368335640Shselasky#ifndef IPV6_V6ONLY
369335640Shselasky  /* For older systems */
370335640Shselasky  #define IPV6_V6ONLY IPV6_BINDV6ONLY
371335640Shselasky#endif /* IPV6_V6ONLY */
372335640Shselasky		if (addrinfo->ai_family == PF_INET6)
373335640Shselasky		{
374335640Shselasky			if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
375335640Shselasky			    (char *)&on, sizeof (int)) == -1)
376335640Shselasky			{
377335640Shselasky				if (errbuf)
378335640Shselasky					pcap_snprintf(errbuf, errbuflen, "setsockopt(IPV6_V6ONLY)");
379335640Shselasky				closesocket(sock);
380335640Shselasky				return INVALID_SOCKET;
381335640Shselasky			}
382335640Shselasky		}
383335640Shselasky#endif /* defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY) */
384335640Shselasky
385335640Shselasky		/* WARNING: if the address is a mcast one, I should place the proper Win32 code here */
386335640Shselasky		if (bind(sock, addrinfo->ai_addr, (int) addrinfo->ai_addrlen) != 0)
387335640Shselasky		{
388356341Scy			sock_geterror("bind()", errbuf, errbuflen);
389335640Shselasky			closesocket(sock);
390335640Shselasky			return INVALID_SOCKET;
391335640Shselasky		}
392335640Shselasky
393335640Shselasky		if (addrinfo->ai_socktype == SOCK_STREAM)
394335640Shselasky			if (listen(sock, nconn) == -1)
395335640Shselasky			{
396356341Scy				sock_geterror("listen()", errbuf, errbuflen);
397335640Shselasky				closesocket(sock);
398335640Shselasky				return INVALID_SOCKET;
399335640Shselasky			}
400335640Shselasky
401335640Shselasky		/* server side ended */
402335640Shselasky		return sock;
403335640Shselasky	}
404335640Shselasky	else	/* we're the client */
405335640Shselasky	{
406335640Shselasky		struct addrinfo *tempaddrinfo;
407335640Shselasky		char *errbufptr;
408335640Shselasky		size_t bufspaceleft;
409335640Shselasky
410335640Shselasky		tempaddrinfo = addrinfo;
411335640Shselasky		errbufptr = errbuf;
412335640Shselasky		bufspaceleft = errbuflen;
413335640Shselasky		*errbufptr = 0;
414335640Shselasky
415335640Shselasky		/*
416335640Shselasky		 * We have to loop though all the addinfo returned.
417335640Shselasky		 * For instance, we can have both IPv6 and IPv4 addresses, but the service we're trying
418335640Shselasky		 * to connect to is unavailable in IPv6, so we have to try in IPv4 as well
419335640Shselasky		 */
420335640Shselasky		while (tempaddrinfo)
421335640Shselasky		{
422335640Shselasky
423335640Shselasky			if (connect(sock, tempaddrinfo->ai_addr, (int) tempaddrinfo->ai_addrlen) == -1)
424335640Shselasky			{
425335640Shselasky				size_t msglen;
426335640Shselasky				char TmpBuffer[100];
427335640Shselasky				char SocketErrorMessage[SOCK_ERRBUF_SIZE];
428335640Shselasky
429335640Shselasky				/*
430335640Shselasky				 * We have to retrieve the error message before any other socket call completes, otherwise
431335640Shselasky				 * the error message is lost
432335640Shselasky				 */
433356341Scy				sock_geterror("Connect to socket failed",
434356341Scy				    SocketErrorMessage, sizeof(SocketErrorMessage));
435335640Shselasky
436335640Shselasky				/* Returns the numeric address of the host that triggered the error */
437335640Shselasky				sock_getascii_addrport((struct sockaddr_storage *) tempaddrinfo->ai_addr, TmpBuffer, sizeof(TmpBuffer), NULL, 0, NI_NUMERICHOST, TmpBuffer, sizeof(TmpBuffer));
438335640Shselasky
439335640Shselasky				pcap_snprintf(errbufptr, bufspaceleft,
440356341Scy				    "Is the server properly installed on %s?  %s", TmpBuffer, SocketErrorMessage);
441335640Shselasky
442335640Shselasky				/* In case more then one 'connect' fails, we manage to keep all the error messages */
443335640Shselasky				msglen = strlen(errbufptr);
444335640Shselasky
445335640Shselasky				errbufptr[msglen] = ' ';
446335640Shselasky				errbufptr[msglen + 1] = 0;
447335640Shselasky
448335640Shselasky				bufspaceleft = bufspaceleft - (msglen + 1);
449335640Shselasky				errbufptr += (msglen + 1);
450335640Shselasky
451335640Shselasky				tempaddrinfo = tempaddrinfo->ai_next;
452335640Shselasky			}
453335640Shselasky			else
454335640Shselasky				break;
455335640Shselasky		}
456335640Shselasky
457335640Shselasky		/*
458335640Shselasky		 * Check how we exit from the previous loop
459335640Shselasky		 * If tempaddrinfo is equal to NULL, it means that all the connect() failed.
460335640Shselasky		 */
461335640Shselasky		if (tempaddrinfo == NULL)
462335640Shselasky		{
463335640Shselasky			closesocket(sock);
464335640Shselasky			return INVALID_SOCKET;
465335640Shselasky		}
466335640Shselasky		else
467335640Shselasky			return sock;
468335640Shselasky	}
469335640Shselasky}
470335640Shselasky
471335640Shselasky/*
472335640Shselasky * \brief Closes the present (TCP and UDP) socket connection.
473335640Shselasky *
474335640Shselasky * This function sends a shutdown() on the socket in order to disable send() calls
475335640Shselasky * (while recv() ones are still allowed). Then, it closes the socket.
476335640Shselasky *
477335640Shselasky * \param sock: the socket identifier of the connection that has to be closed.
478335640Shselasky *
479335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
480335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
481335640Shselasky * It can be NULL; in this case the error cannot be printed.
482335640Shselasky *
483335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
484335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
485335640Shselasky *
486335640Shselasky * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned
487335640Shselasky * in the 'errbuf' variable.
488335640Shselasky */
489335640Shselaskyint sock_close(SOCKET sock, char *errbuf, int errbuflen)
490335640Shselasky{
491335640Shselasky	/*
492335640Shselasky	 * SHUT_WR: subsequent calls to the send function are disallowed.
493335640Shselasky	 * For TCP sockets, a FIN will be sent after all data is sent and
494335640Shselasky	 * acknowledged by the Server.
495335640Shselasky	 */
496335640Shselasky	if (shutdown(sock, SHUT_WR))
497335640Shselasky	{
498356341Scy		sock_geterror("shutdown()", errbuf, errbuflen);
499335640Shselasky		/* close the socket anyway */
500335640Shselasky		closesocket(sock);
501335640Shselasky		return -1;
502335640Shselasky	}
503335640Shselasky
504335640Shselasky	closesocket(sock);
505335640Shselasky	return 0;
506335640Shselasky}
507335640Shselasky
508335640Shselasky/*
509356341Scy * gai_errstring() has some problems:
510356341Scy *
511356341Scy * 1) on Windows, Microsoft explicitly says it's not thread-safe;
512356341Scy * 2) on UN*X, the Single UNIX Specification doesn't say it *is*
513356341Scy *    thread-safe, so an implementation might use a static buffer
514356341Scy *    for unknown error codes;
515356341Scy * 3) the error message for the most likely error, EAI_NONAME, is
516356341Scy *    truly horrible on several platforms ("nodename nor servname
517356341Scy *    provided, or not known"?  It's typically going to be "not
518356341Scy *    known", not "oopsie, I passed null pointers for the host name
519356341Scy *    and service name", not to mention they forgot the "neither");
520356341Scy *
521356341Scy * so we roll our own.
522356341Scy */
523356341Scystatic void
524356341Scyget_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err,
525356341Scy    const char *hostname, const char *portname)
526356341Scy{
527356341Scy	char hostport[PCAP_ERRBUF_SIZE];
528356341Scy
529356341Scy	if (hostname != NULL && portname != NULL)
530356341Scy		pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "%s:%s",
531356341Scy		    hostname, portname);
532356341Scy	else if (hostname != NULL)
533356341Scy		pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "%s",
534356341Scy		    hostname);
535356341Scy	else if (portname != NULL)
536356341Scy		pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, ":%s",
537356341Scy		    portname);
538356341Scy	else
539356341Scy		pcap_snprintf(hostport, PCAP_ERRBUF_SIZE, "<no host or port!>");
540356341Scy	switch (err)
541356341Scy	{
542356341Scy#ifdef EAI_ADDRFAMILY
543356341Scy		case EAI_ADDRFAMILY:
544356341Scy			pcap_snprintf(errbuf, errbuflen,
545356341Scy			    "%sAddress family for %s not supported",
546356341Scy			    prefix, hostport);
547356341Scy			break;
548356341Scy#endif
549356341Scy
550356341Scy		case EAI_AGAIN:
551356341Scy			pcap_snprintf(errbuf, errbuflen,
552356341Scy			    "%s%s could not be resolved at this time",
553356341Scy			    prefix, hostport);
554356341Scy			break;
555356341Scy
556356341Scy		case EAI_BADFLAGS:
557356341Scy			pcap_snprintf(errbuf, errbuflen,
558356341Scy			    "%sThe ai_flags parameter for looking up %s had an invalid value",
559356341Scy			    prefix, hostport);
560356341Scy			break;
561356341Scy
562356341Scy		case EAI_FAIL:
563356341Scy			pcap_snprintf(errbuf, errbuflen,
564356341Scy			    "%sA non-recoverable error occurred when attempting to resolve %s",
565356341Scy			    prefix, hostport);
566356341Scy			break;
567356341Scy
568356341Scy		case EAI_FAMILY:
569356341Scy			pcap_snprintf(errbuf, errbuflen,
570356341Scy			    "%sThe address family for looking up %s was not recognized",
571356341Scy			    prefix, hostport);
572356341Scy			break;
573356341Scy
574356341Scy		case EAI_MEMORY:
575356341Scy			pcap_snprintf(errbuf, errbuflen,
576356341Scy			    "%sOut of memory trying to allocate storage when looking up %s",
577356341Scy			    prefix, hostport);
578356341Scy			break;
579356341Scy
580356341Scy		/*
581356341Scy		 * RFC 2553 had both EAI_NODATA and EAI_NONAME.
582356341Scy		 *
583356341Scy		 * RFC 3493 has only EAI_NONAME.
584356341Scy		 *
585356341Scy		 * Some implementations define EAI_NODATA and EAI_NONAME
586356341Scy		 * to the same value, others don't.  If EAI_NODATA is
587356341Scy		 * defined and isn't the same as EAI_NONAME, we handle
588356341Scy		 * EAI_NODATA.
589356341Scy		 */
590356341Scy#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
591356341Scy		case EAI_NODATA:
592356341Scy			pcap_snprintf(errbuf, errbuflen,
593356341Scy			    "%sNo address associated with %s",
594356341Scy			    prefix, hostport);
595356341Scy			break;
596356341Scy#endif
597356341Scy
598356341Scy		case EAI_NONAME:
599356341Scy			pcap_snprintf(errbuf, errbuflen,
600356341Scy			    "%sThe host name %s couldn't be resolved",
601356341Scy			    prefix, hostport);
602356341Scy			break;
603356341Scy
604356341Scy		case EAI_SERVICE:
605356341Scy			pcap_snprintf(errbuf, errbuflen,
606356341Scy			    "%sThe service value specified when looking up %s as not recognized for the socket type",
607356341Scy			    prefix, hostport);
608356341Scy			break;
609356341Scy
610356341Scy		case EAI_SOCKTYPE:
611356341Scy			pcap_snprintf(errbuf, errbuflen,
612356341Scy			    "%sThe socket type specified when looking up %s as not recognized",
613356341Scy			    prefix, hostport);
614356341Scy			break;
615356341Scy
616356341Scy#ifdef EAI_SYSTEM
617356341Scy		case EAI_SYSTEM:
618356341Scy			/*
619356341Scy			 * Assumed to be UN*X.
620356341Scy			 */
621356341Scy			pcap_snprintf(errbuf, errbuflen,
622356341Scy			    "%sAn error occurred when looking up %s: %s",
623356341Scy			    prefix, hostport, pcap_strerror(errno));
624356341Scy			break;
625356341Scy#endif
626356341Scy
627356341Scy#ifdef EAI_BADHINTS
628356341Scy		case EAI_BADHINTS:
629356341Scy			pcap_snprintf(errbuf, errbuflen,
630356341Scy			    "%sInvalid value for hints when looking up %s",
631356341Scy			    prefix, hostport);
632356341Scy			break;
633356341Scy#endif
634356341Scy
635356341Scy#ifdef EAI_PROTOCOL
636356341Scy		case EAI_PROTOCOL:
637356341Scy			pcap_snprintf(errbuf, errbuflen,
638356341Scy			    "%sResolved protocol when looking up %s is unknown",
639356341Scy			    prefix, hostport);
640356341Scy			break;
641356341Scy#endif
642356341Scy
643356341Scy#ifdef EAI_OVERFLOW
644356341Scy		case EAI_OVERFLOW:
645356341Scy			pcap_snprintf(errbuf, errbuflen,
646356341Scy			    "%sArgument buffer overflow when looking up %s",
647356341Scy			    prefix, hostport);
648356341Scy			break;
649356341Scy#endif
650356341Scy
651356341Scy		default:
652356341Scy			pcap_snprintf(errbuf, errbuflen,
653356341Scy			    "%sgetaddrinfo() error %d when looking up %s",
654356341Scy			    prefix, err, hostport);
655356341Scy			break;
656356341Scy	}
657356341Scy}
658356341Scy
659356341Scy/*
660335640Shselasky * \brief Checks that the address, port and flags given are valids and it returns an 'addrinfo' structure.
661335640Shselasky *
662335640Shselasky * This function basically calls the getaddrinfo() calls, and it performs a set of sanity checks
663335640Shselasky * to control that everything is fine (e.g. a TCP socket cannot have a mcast address, and such).
664335640Shselasky * If an error occurs, it writes the error message into 'errbuf'.
665335640Shselasky *
666335640Shselasky * \param host: a pointer to a string identifying the host. It can be
667335640Shselasky * a host name, a numeric literal address, or NULL or "" (useful
668335640Shselasky * in case of a server socket which has to bind to all addresses).
669335640Shselasky *
670335640Shselasky * \param port: a pointer to a user-allocated buffer containing the network port to use.
671335640Shselasky *
672335640Shselasky * \param hints: an addrinfo variable (passed by reference) containing the flags needed to create the
673335640Shselasky * addrinfo structure appropriately.
674335640Shselasky *
675335640Shselasky * \param addrinfo: it represents the true returning value. This is a pointer to an addrinfo variable
676335640Shselasky * (passed by reference), which will be allocated by this function and returned back to the caller.
677335640Shselasky * This variable will be used in the next sockets calls.
678335640Shselasky *
679335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
680335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
681335640Shselasky * It can be NULL; in this case the error cannot be printed.
682335640Shselasky *
683335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
684335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
685335640Shselasky *
686335640Shselasky * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned
687335640Shselasky * in the 'errbuf' variable. The addrinfo variable that has to be used in the following sockets calls is
688335640Shselasky * returned into the addrinfo parameter.
689335640Shselasky *
690335640Shselasky * \warning The 'addrinfo' variable has to be deleted by the programmer by calling freeaddrinfo() when
691335640Shselasky * it is no longer needed.
692335640Shselasky *
693335640Shselasky * \warning This function requires the 'hints' variable as parameter. The semantic of this variable is the same
694335640Shselasky * of the one of the corresponding variable used into the standard getaddrinfo() socket function. We suggest
695335640Shselasky * the programmer to look at that function in order to set the 'hints' variable appropriately.
696335640Shselasky */
697335640Shselaskyint sock_initaddress(const char *host, const char *port,
698335640Shselasky    struct addrinfo *hints, struct addrinfo **addrinfo, char *errbuf, int errbuflen)
699335640Shselasky{
700335640Shselasky	int retval;
701335640Shselasky
702335640Shselasky	retval = getaddrinfo(host, port, hints, addrinfo);
703335640Shselasky	if (retval != 0)
704335640Shselasky	{
705335640Shselasky		if (errbuf)
706335640Shselasky		{
707356341Scy			get_gai_errstring(errbuf, errbuflen, "", retval,
708356341Scy			    host, port);
709335640Shselasky		}
710335640Shselasky		return -1;
711335640Shselasky	}
712335640Shselasky	/*
713335640Shselasky	 * \warning SOCKET: I should check all the accept() in order to bind to all addresses in case
714335640Shselasky	 * addrinfo has more han one pointers
715335640Shselasky	 */
716335640Shselasky
717335640Shselasky	/*
718335640Shselasky	 * This software only supports PF_INET and PF_INET6.
719335640Shselasky	 *
720335640Shselasky	 * XXX - should we just check that at least *one* address is
721335640Shselasky	 * either PF_INET or PF_INET6, and, when using the list,
722335640Shselasky	 * ignore all addresses that are neither?  (What, no IPX
723335640Shselasky	 * support? :-))
724335640Shselasky	 */
725335640Shselasky	if (((*addrinfo)->ai_family != PF_INET) &&
726335640Shselasky	    ((*addrinfo)->ai_family != PF_INET6))
727335640Shselasky	{
728335640Shselasky		if (errbuf)
729335640Shselasky			pcap_snprintf(errbuf, errbuflen, "getaddrinfo(): socket type not supported");
730335640Shselasky		freeaddrinfo(*addrinfo);
731335640Shselasky		*addrinfo = NULL;
732335640Shselasky		return -1;
733335640Shselasky	}
734335640Shselasky
735335640Shselasky	/*
736335640Shselasky	 * You can't do multicast (or broadcast) TCP.
737335640Shselasky	 */
738335640Shselasky	if (((*addrinfo)->ai_socktype == SOCK_STREAM) &&
739335640Shselasky	    (sock_ismcastaddr((*addrinfo)->ai_addr) == 0))
740335640Shselasky	{
741335640Shselasky		if (errbuf)
742335640Shselasky			pcap_snprintf(errbuf, errbuflen, "getaddrinfo(): multicast addresses are not valid when using TCP streams");
743335640Shselasky		freeaddrinfo(*addrinfo);
744335640Shselasky		*addrinfo = NULL;
745335640Shselasky		return -1;
746335640Shselasky	}
747335640Shselasky
748335640Shselasky	return 0;
749335640Shselasky}
750335640Shselasky
751335640Shselasky/*
752335640Shselasky * \brief It sends the amount of data contained into 'buffer' on the given socket.
753335640Shselasky *
754335640Shselasky * This function basically calls the send() socket function and it checks that all
755335640Shselasky * the data specified in 'buffer' (of size 'size') will be sent. If an error occurs,
756335640Shselasky * it writes the error message into 'errbuf'.
757335640Shselasky * In case the socket buffer does not have enough space, it loops until all data
758335640Shselasky * has been sent.
759335640Shselasky *
760335640Shselasky * \param socket: the connected socket currently opened.
761335640Shselasky *
762335640Shselasky * \param buffer: a char pointer to a user-allocated buffer in which data is contained.
763335640Shselasky *
764335640Shselasky * \param size: number of bytes that have to be sent.
765335640Shselasky *
766335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
767335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
768335640Shselasky * It can be NULL; in this case the error cannot be printed.
769335640Shselasky *
770335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
771335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
772335640Shselasky *
773335640Shselasky * \return '0' if everything is fine, '-1' if an error other than
774335640Shselasky * "connection reset" or "peer has closed the receive side" occurred,
775335640Shselasky * '-2' if we got one of those errors.
776335640Shselasky * For errors, an error message is returned in the 'errbuf' variable.
777335640Shselasky */
778335640Shselaskyint sock_send(SOCKET sock, const char *buffer, size_t size,
779335640Shselasky    char *errbuf, int errbuflen)
780335640Shselasky{
781335640Shselasky	int remaining;
782335640Shselasky	ssize_t nsent;
783335640Shselasky
784335640Shselasky	if (size > INT_MAX)
785335640Shselasky	{
786335640Shselasky		if (errbuf)
787335640Shselasky		{
788335640Shselasky			pcap_snprintf(errbuf, errbuflen,
789356341Scy			    "Can't send more than %u bytes with sock_send",
790335640Shselasky			    INT_MAX);
791335640Shselasky		}
792335640Shselasky		return -1;
793335640Shselasky	}
794335640Shselasky	remaining = (int)size;
795335640Shselasky
796335640Shselasky	do {
797335640Shselasky#ifdef MSG_NOSIGNAL
798335640Shselasky		/*
799335640Shselasky		 * Send with MSG_NOSIGNAL, so that we don't get SIGPIPE
800335640Shselasky		 * on errors on stream-oriented sockets when the other
801335640Shselasky		 * end breaks the connection.
802335640Shselasky		 * The EPIPE error is still returned.
803335640Shselasky		 */
804335640Shselasky		nsent = send(sock, buffer, remaining, MSG_NOSIGNAL);
805335640Shselasky#else
806335640Shselasky		nsent = send(sock, buffer, remaining, 0);
807335640Shselasky#endif
808335640Shselasky
809335640Shselasky		if (nsent == -1)
810335640Shselasky		{
811335640Shselasky			/*
812335640Shselasky			 * If the client closed the connection out from
813335640Shselasky			 * under us, there's no need to log that as an
814335640Shselasky			 * error.
815335640Shselasky			 */
816335640Shselasky			int errcode;
817335640Shselasky
818335640Shselasky#ifdef _WIN32
819335640Shselasky			errcode = GetLastError();
820335640Shselasky			if (errcode == WSAECONNRESET ||
821335640Shselasky			    errcode == WSAECONNABORTED)
822335640Shselasky			{
823335640Shselasky				/*
824335640Shselasky				 * WSAECONNABORTED appears to be the error
825335640Shselasky				 * returned in Winsock when you try to send
826335640Shselasky				 * on a connection where the peer has closed
827335640Shselasky				 * the receive side.
828335640Shselasky				 */
829335640Shselasky				return -2;
830335640Shselasky			}
831356341Scy			sock_fmterror("send()", errcode, errbuf, errbuflen);
832335640Shselasky#else
833335640Shselasky			errcode = errno;
834335640Shselasky			if (errcode == ECONNRESET || errcode == EPIPE)
835335640Shselasky			{
836335640Shselasky				/*
837335640Shselasky				 * EPIPE is what's returned on UN*X when
838335640Shselasky				 * you try to send on a connection when
839335640Shselasky				 * the peer has closed the receive side.
840335640Shselasky				 */
841335640Shselasky				return -2;
842335640Shselasky			}
843356341Scy			sock_fmterror("send()", errcode, errbuf, errbuflen);
844335640Shselasky#endif
845335640Shselasky			return -1;
846335640Shselasky		}
847335640Shselasky
848335640Shselasky		remaining -= nsent;
849335640Shselasky		buffer += nsent;
850335640Shselasky	} while (remaining != 0);
851335640Shselasky
852335640Shselasky	return 0;
853335640Shselasky}
854335640Shselasky
855335640Shselasky/*
856335640Shselasky * \brief It copies the amount of data contained into 'buffer' into 'tempbuf'.
857335640Shselasky * and it checks for buffer overflows.
858335640Shselasky *
859335640Shselasky * This function basically copies 'size' bytes of data contained into 'buffer'
860335640Shselasky * into 'tempbuf', starting at offset 'offset'. Before that, it checks that the
861335640Shselasky * resulting buffer will not be larger	than 'totsize'. Finally, it updates
862335640Shselasky * the 'offset' variable in order to point to the first empty location of the buffer.
863335640Shselasky *
864335640Shselasky * In case the function is called with 'checkonly' equal to 1, it does not copy
865335640Shselasky * the data into the buffer. It only checks for buffer overflows and it updates the
866335640Shselasky * 'offset' variable. This mode can be useful when the buffer already contains the
867335640Shselasky * data (maybe because the producer writes directly into the target buffer), so
868335640Shselasky * only the buffer overflow check has to be made.
869335640Shselasky * In this case, both 'buffer' and 'tempbuf' can be NULL values.
870335640Shselasky *
871335640Shselasky * This function is useful in case the userland application does not know immediately
872335640Shselasky * all the data it has to write into the socket. This function provides a way to create
873335640Shselasky * the "stream" step by step, appending the new data to the old one. Then, when all the
874335640Shselasky * data has been bufferized, the application can call the sock_send() function.
875335640Shselasky *
876335640Shselasky * \param buffer: a char pointer to a user-allocated buffer that keeps the data
877335640Shselasky * that has to be copied.
878335640Shselasky *
879335640Shselasky * \param size: number of bytes that have to be copied.
880335640Shselasky *
881335640Shselasky * \param tempbuf: user-allocated buffer (of size 'totsize') in which data
882335640Shselasky * has to be copied.
883335640Shselasky *
884335640Shselasky * \param offset: an index into 'tempbuf' which keeps the location of its first
885335640Shselasky * empty location.
886335640Shselasky *
887335640Shselasky * \param totsize: total size of the buffer in which data is being copied.
888335640Shselasky *
889335640Shselasky * \param checkonly: '1' if we do not want to copy data into the buffer and we
890335640Shselasky * want just do a buffer ovreflow control, '0' if data has to be copied as well.
891335640Shselasky *
892335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
893335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
894335640Shselasky * It can be NULL; in this case the error cannot be printed.
895335640Shselasky *
896335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
897335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
898335640Shselasky *
899335640Shselasky * \return '0' if everything is fine, '-1' if some errors occurred. The error message
900335640Shselasky * is returned in the 'errbuf' variable. When the function returns, 'tempbuf' will
901335640Shselasky * have the new string appended, and 'offset' will keep the length of that buffer.
902335640Shselasky * In case of 'checkonly == 1', data is not copied, but 'offset' is updated in any case.
903335640Shselasky *
904335640Shselasky * \warning This function assumes that the buffer in which data has to be stored is
905335640Shselasky * large 'totbuf' bytes.
906335640Shselasky *
907335640Shselasky * \warning In case of 'checkonly', be carefully to call this function *before* copying
908335640Shselasky * the data into the buffer. Otherwise, the control about the buffer overflow is useless.
909335640Shselasky */
910335640Shselaskyint sock_bufferize(const char *buffer, int size, char *tempbuf, int *offset, int totsize, int checkonly, char *errbuf, int errbuflen)
911335640Shselasky{
912335640Shselasky	if ((*offset + size) > totsize)
913335640Shselasky	{
914335640Shselasky		if (errbuf)
915335640Shselasky			pcap_snprintf(errbuf, errbuflen, "Not enough space in the temporary send buffer.");
916335640Shselasky		return -1;
917335640Shselasky	}
918335640Shselasky
919335640Shselasky	if (!checkonly)
920335640Shselasky		memcpy(tempbuf + (*offset), buffer, size);
921335640Shselasky
922335640Shselasky	(*offset) += size;
923335640Shselasky
924335640Shselasky	return 0;
925335640Shselasky}
926335640Shselasky
927335640Shselasky/*
928335640Shselasky * \brief It waits on a connected socket and it manages to receive data.
929335640Shselasky *
930335640Shselasky * This function basically calls the recv() socket function and it checks that no
931335640Shselasky * error occurred. If that happens, it writes the error message into 'errbuf'.
932335640Shselasky *
933335640Shselasky * This function changes its behavior according to the 'receiveall' flag: if we
934335640Shselasky * want to receive exactly 'size' byte, it loops on the recv()	until all the requested
935335640Shselasky * data is arrived. Otherwise, it returns the data currently available.
936335640Shselasky *
937335640Shselasky * In case the socket does not have enough data available, it cycles on the recv()
938335640Shselasky * until the requested data (of size 'size') is arrived.
939335640Shselasky * In this case, it blocks until the number of bytes read is equal to 'size'.
940335640Shselasky *
941335640Shselasky * \param sock: the connected socket currently opened.
942335640Shselasky *
943335640Shselasky * \param buffer: a char pointer to a user-allocated buffer in which data has to be stored
944335640Shselasky *
945335640Shselasky * \param size: size of the allocated buffer. WARNING: this indicates the number of bytes
946335640Shselasky * that we are expecting to be read.
947335640Shselasky *
948335640Shselasky * \param flags:
949335640Shselasky *
950335640Shselasky *   SOCK_RECEIVALL_XXX:
951335640Shselasky *
952335640Shselasky * 	if SOCK_RECEIVEALL_NO, return as soon as some data is ready
953335640Shselasky *	if SOCK_RECEIVALL_YES, wait until 'size' data has been
954335640Shselasky *	    received (in case the socket does not have enough data available).
955335640Shselasky *
956335640Shselasky *   SOCK_EOF_XXX:
957335640Shselasky *
958335640Shselasky *	if SOCK_EOF_ISNT_ERROR, if the first read returns 0, just return 0,
959335640Shselasky *	    and return an error on any subsequent read that returns 0;
960335640Shselasky *	if SOCK_EOF_IS_ERROR, if any read returns 0, return an error.
961335640Shselasky *
962335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
963335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
964335640Shselasky * It can be NULL; in this case the error cannot be printed.
965335640Shselasky *
966335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
967335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
968335640Shselasky *
969335640Shselasky * \return the number of bytes read if everything is fine, '-1' if some errors occurred.
970335640Shselasky * The error message is returned in the 'errbuf' variable.
971335640Shselasky */
972335640Shselasky
973335640Shselaskyint sock_recv(SOCKET sock, void *buffer, size_t size, int flags,
974335640Shselasky    char *errbuf, int errbuflen)
975335640Shselasky{
976335640Shselasky	char *bufp = buffer;
977335640Shselasky	int remaining;
978335640Shselasky	ssize_t nread;
979335640Shselasky
980335640Shselasky	if (size == 0)
981335640Shselasky	{
982335640Shselasky		return 0;
983335640Shselasky	}
984335640Shselasky	if (size > INT_MAX)
985335640Shselasky	{
986335640Shselasky		if (errbuf)
987335640Shselasky		{
988335640Shselasky			pcap_snprintf(errbuf, errbuflen,
989335640Shselasky			    "Can't read more than %u bytes with sock_recv",
990335640Shselasky			    INT_MAX);
991335640Shselasky		}
992335640Shselasky		return -1;
993335640Shselasky	}
994335640Shselasky
995335640Shselasky	bufp = (char *) buffer;
996335640Shselasky	remaining = (int) size;
997335640Shselasky
998335640Shselasky	/*
999335640Shselasky	 * We don't use MSG_WAITALL because it's not supported in
1000335640Shselasky	 * Win32.
1001335640Shselasky	 */
1002335640Shselasky	for (;;) {
1003335640Shselasky		nread = recv(sock, bufp, remaining, 0);
1004335640Shselasky
1005335640Shselasky		if (nread == -1)
1006335640Shselasky		{
1007335640Shselasky#ifndef _WIN32
1008335640Shselasky			if (errno == EINTR)
1009335640Shselasky				return -3;
1010335640Shselasky#endif
1011356341Scy			sock_geterror("recv()", errbuf, errbuflen);
1012335640Shselasky			return -1;
1013335640Shselasky		}
1014335640Shselasky
1015335640Shselasky		if (nread == 0)
1016335640Shselasky		{
1017335640Shselasky			if ((flags & SOCK_EOF_IS_ERROR) ||
1018335640Shselasky			    (remaining != (int) size))
1019335640Shselasky			{
1020335640Shselasky				/*
1021335640Shselasky				 * Either we've already read some data,
1022335640Shselasky				 * or we're always supposed to return
1023335640Shselasky				 * an error on EOF.
1024335640Shselasky				 */
1025335640Shselasky				if (errbuf)
1026335640Shselasky				{
1027335640Shselasky					pcap_snprintf(errbuf, errbuflen,
1028335640Shselasky					    "The other host terminated the connection.");
1029335640Shselasky				}
1030335640Shselasky				return -1;
1031335640Shselasky			}
1032335640Shselasky			else
1033335640Shselasky				return 0;
1034335640Shselasky		}
1035335640Shselasky
1036335640Shselasky		/*
1037335640Shselasky		 * Do we want to read the amount requested, or just return
1038335640Shselasky		 * what we got?
1039335640Shselasky		 */
1040335640Shselasky		if (!(flags & SOCK_RECEIVEALL_YES))
1041335640Shselasky		{
1042335640Shselasky			/*
1043335640Shselasky			 * Just return what we got.
1044335640Shselasky			 */
1045335640Shselasky			return (int) nread;
1046335640Shselasky		}
1047335640Shselasky
1048335640Shselasky		bufp += nread;
1049335640Shselasky		remaining -= nread;
1050335640Shselasky
1051335640Shselasky		if (remaining == 0)
1052335640Shselasky			return (int) size;
1053335640Shselasky	}
1054335640Shselasky}
1055335640Shselasky
1056335640Shselasky/*
1057335640Shselasky * Receives a datagram from a socket.
1058335640Shselasky *
1059335640Shselasky * Returns the size of the datagram on success or -1 on error.
1060335640Shselasky */
1061335640Shselaskyint sock_recv_dgram(SOCKET sock, void *buffer, size_t size,
1062335640Shselasky    char *errbuf, int errbuflen)
1063335640Shselasky{
1064335640Shselasky	ssize_t nread;
1065335640Shselasky#ifndef _WIN32
1066335640Shselasky	struct msghdr message;
1067335640Shselasky	struct iovec iov;
1068335640Shselasky#endif
1069335640Shselasky
1070335640Shselasky	if (size == 0)
1071335640Shselasky	{
1072335640Shselasky		return 0;
1073335640Shselasky	}
1074335640Shselasky	if (size > INT_MAX)
1075335640Shselasky	{
1076335640Shselasky		if (errbuf)
1077335640Shselasky		{
1078335640Shselasky			pcap_snprintf(errbuf, errbuflen,
1079335640Shselasky			    "Can't read more than %u bytes with sock_recv_dgram",
1080335640Shselasky			    INT_MAX);
1081335640Shselasky		}
1082335640Shselasky		return -1;
1083335640Shselasky	}
1084335640Shselasky
1085335640Shselasky	/*
1086335640Shselasky	 * This should be a datagram socket, so we should get the
1087335640Shselasky	 * entire datagram in one recv() or recvmsg() call, and
1088335640Shselasky	 * don't need to loop.
1089335640Shselasky	 */
1090335640Shselasky#ifdef _WIN32
1091335640Shselasky	nread = recv(sock, buffer, size, 0);
1092335640Shselasky	if (nread == SOCKET_ERROR)
1093335640Shselasky	{
1094335640Shselasky		/*
1095335640Shselasky		 * To quote the MSDN documentation for recv(),
1096335640Shselasky		 * "If the datagram or message is larger than
1097335640Shselasky		 * the buffer specified, the buffer is filled
1098335640Shselasky		 * with the first part of the datagram, and recv
1099335640Shselasky		 * generates the error WSAEMSGSIZE. For unreliable
1100335640Shselasky		 * protocols (for example, UDP) the excess data is
1101335640Shselasky		 * lost..."
1102335640Shselasky		 *
1103335640Shselasky		 * So if the message is bigger than the buffer
1104335640Shselasky		 * supplied to us, the excess data is discarded,
1105335640Shselasky		 * and we'll report an error.
1106335640Shselasky		 */
1107356341Scy		sock_geterror("recv()", errbuf, errbuflen);
1108335640Shselasky		return -1;
1109335640Shselasky	}
1110335640Shselasky#else /* _WIN32 */
1111335640Shselasky	/*
1112335640Shselasky	 * The Single UNIX Specification says that a recv() on
1113335640Shselasky	 * a socket for a message-oriented protocol will discard
1114335640Shselasky	 * the excess data.  It does *not* indicate that the
1115335640Shselasky	 * receive will fail with, for example, EMSGSIZE.
1116335640Shselasky	 *
1117335640Shselasky	 * Therefore, we use recvmsg(), which appears to be
1118335640Shselasky	 * the only way to get a "message truncated" indication
1119335640Shselasky	 * when receiving a message for a message-oriented
1120335640Shselasky	 * protocol.
1121335640Shselasky	 */
1122335640Shselasky	message.msg_name = NULL;	/* we don't care who it's from */
1123335640Shselasky	message.msg_namelen = 0;
1124335640Shselasky	iov.iov_base = buffer;
1125335640Shselasky	iov.iov_len = size;
1126335640Shselasky	message.msg_iov = &iov;
1127335640Shselasky	message.msg_iovlen = 1;
1128335640Shselasky#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
1129335640Shselasky	message.msg_control = NULL;	/* we don't care about control information */
1130335640Shselasky	message.msg_controllen = 0;
1131335640Shselasky#endif
1132335640Shselasky#ifdef HAVE_STRUCT_MSGHDR_MSG_FLAGS
1133335640Shselasky	message.msg_flags = 0;
1134335640Shselasky#endif
1135335640Shselasky	nread = recvmsg(sock, &message, 0);
1136335640Shselasky	if (nread == -1)
1137335640Shselasky	{
1138335640Shselasky		if (errno == EINTR)
1139335640Shselasky			return -3;
1140356341Scy		sock_geterror("recv()", errbuf, errbuflen);
1141335640Shselasky		return -1;
1142335640Shselasky	}
1143335640Shselasky#ifdef HAVE_STRUCT_MSGHDR_MSG_FLAGS
1144335640Shselasky	/*
1145335640Shselasky	 * XXX - Solaris supports this, but only if you ask for the
1146335640Shselasky	 * X/Open version of recvmsg(); should we use that, or will
1147335640Shselasky	 * that cause other problems?
1148335640Shselasky	 */
1149335640Shselasky	if (message.msg_flags & MSG_TRUNC)
1150335640Shselasky	{
1151335640Shselasky		/*
1152335640Shselasky		 * Message was bigger than the specified buffer size.
1153335640Shselasky		 *
1154335640Shselasky		 * Report this as an error, as the Microsoft documentation
1155335640Shselasky		 * implies we'd do in a similar case on Windows.
1156335640Shselasky		 */
1157335640Shselasky		pcap_snprintf(errbuf, errbuflen, "recv(): Message too long");
1158335640Shselasky		return -1;
1159335640Shselasky	}
1160335640Shselasky#endif /* HAVE_STRUCT_MSGHDR_MSG_FLAGS */
1161335640Shselasky#endif /* _WIN32 */
1162335640Shselasky
1163335640Shselasky	/*
1164335640Shselasky	 * The size we're reading fits in an int, so the return value
1165335640Shselasky	 * will fit in an int.
1166335640Shselasky	 */
1167335640Shselasky	return (int)nread;
1168335640Shselasky}
1169335640Shselasky
1170335640Shselasky/*
1171335640Shselasky * \brief It discards N bytes that are currently waiting to be read on the current socket.
1172335640Shselasky *
1173335640Shselasky * This function is useful in case we receive a message we cannot understand (e.g.
1174335640Shselasky * wrong version number when receiving a network packet), so that we have to discard all
1175335640Shselasky * data before reading a new message.
1176335640Shselasky *
1177335640Shselasky * This function will read 'size' bytes from the socket and discard them.
1178335640Shselasky * It defines an internal buffer in which data will be copied; however, in case
1179335640Shselasky * this buffer is not large enough, it will cycle in order to read everything as well.
1180335640Shselasky *
1181335640Shselasky * \param sock: the connected socket currently opened.
1182335640Shselasky *
1183335640Shselasky * \param size: number of bytes that have to be discarded.
1184335640Shselasky *
1185335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
1186335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
1187335640Shselasky * It can be NULL; in this case the error cannot be printed.
1188335640Shselasky *
1189335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
1190335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
1191335640Shselasky *
1192335640Shselasky * \return '0' if everything is fine, '-1' if some errors occurred.
1193335640Shselasky * The error message is returned in the 'errbuf' variable.
1194335640Shselasky */
1195335640Shselaskyint sock_discard(SOCKET sock, int size, char *errbuf, int errbuflen)
1196335640Shselasky{
1197335640Shselasky#define TEMP_BUF_SIZE 32768
1198335640Shselasky
1199335640Shselasky	char buffer[TEMP_BUF_SIZE];		/* network buffer, to be used when the message is discarded */
1200335640Shselasky
1201335640Shselasky	/*
1202335640Shselasky	 * A static allocation avoids the need of a 'malloc()' each time we want to discard a message
1203335640Shselasky	 * Our feeling is that a buffer if 32KB is enough for most of the application;
1204335640Shselasky	 * in case this is not enough, the "while" loop discards the message by calling the
1205335640Shselasky	 * sockrecv() several times.
1206335640Shselasky	 * We do not want to create a bigger variable because this causes the program to exit on
1207335640Shselasky	 * some platforms (e.g. BSD)
1208335640Shselasky	 */
1209335640Shselasky	while (size > TEMP_BUF_SIZE)
1210335640Shselasky	{
1211335640Shselasky		if (sock_recv(sock, buffer, TEMP_BUF_SIZE, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
1212335640Shselasky			return -1;
1213335640Shselasky
1214335640Shselasky		size -= TEMP_BUF_SIZE;
1215335640Shselasky	}
1216335640Shselasky
1217335640Shselasky	/*
1218335640Shselasky	 * If there is still data to be discarded
1219335640Shselasky	 * In this case, the data can fit into the temporary buffer
1220335640Shselasky	 */
1221335640Shselasky	if (size)
1222335640Shselasky	{
1223335640Shselasky		if (sock_recv(sock, buffer, size, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1)
1224335640Shselasky			return -1;
1225335640Shselasky	}
1226335640Shselasky
1227335640Shselasky	return 0;
1228335640Shselasky}
1229335640Shselasky
1230335640Shselasky/*
1231335640Shselasky * \brief Checks that one host (identified by the sockaddr_storage structure) belongs to an 'allowed list'.
1232335640Shselasky *
1233335640Shselasky * This function is useful after an accept() call in order to check if the connecting
1234335640Shselasky * host is allowed to connect to me. To do that, we have a buffer that keeps the list of the
1235335640Shselasky * allowed host; this function checks the sockaddr_storage structure of the connecting host
1236335640Shselasky * against this host list, and it returns '0' is the host is included in this list.
1237335640Shselasky *
1238335640Shselasky * \param hostlist: pointer to a string that contains the list of the allowed host.
1239335640Shselasky *
1240335640Shselasky * \param sep: a string that keeps the separators used between the hosts (for example the
1241335640Shselasky * space character) in the host list.
1242335640Shselasky *
1243335640Shselasky * \param from: a sockaddr_storage structure, as it is returned by the accept() call.
1244335640Shselasky *
1245335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
1246335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
1247335640Shselasky * It can be NULL; in this case the error cannot be printed.
1248335640Shselasky *
1249335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
1250335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
1251335640Shselasky *
1252335640Shselasky * \return It returns:
1253335640Shselasky * - '1' if the host list is empty
1254335640Shselasky * - '0' if the host belongs to the host list (and therefore it is allowed to connect)
1255335640Shselasky * - '-1' in case the host does not belong to the host list (and therefore it is not allowed to connect
1256335640Shselasky * - '-2' in case or error. The error message is returned in the 'errbuf' variable.
1257335640Shselasky */
1258335640Shselaskyint sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf, int errbuflen)
1259335640Shselasky{
1260335640Shselasky	/* checks if the connecting host is among the ones allowed */
1261335640Shselasky	if ((hostlist) && (hostlist[0]))
1262335640Shselasky	{
1263335640Shselasky		char *token;					/* temp, needed to separate items into the hostlist */
1264335640Shselasky		struct addrinfo *addrinfo, *ai_next;
1265335640Shselasky		char *temphostlist;
1266335640Shselasky		char *lasts;
1267356341Scy		int getaddrinfo_failed = 0;
1268335640Shselasky
1269335640Shselasky		/*
1270335640Shselasky		 * The problem is that strtok modifies the original variable by putting '0' at the end of each token
1271335640Shselasky		 * So, we have to create a new temporary string in which the original content is kept
1272335640Shselasky		 */
1273335640Shselasky		temphostlist = strdup(hostlist);
1274335640Shselasky		if (temphostlist == NULL)
1275335640Shselasky		{
1276335640Shselasky			sock_geterror("sock_check_hostlist(), malloc() failed", errbuf, errbuflen);
1277335640Shselasky			return -2;
1278335640Shselasky		}
1279335640Shselasky
1280335640Shselasky		token = pcap_strtok_r(temphostlist, sep, &lasts);
1281335640Shselasky
1282335640Shselasky		/* it avoids a warning in the compilation ('addrinfo used but not initialized') */
1283335640Shselasky		addrinfo = NULL;
1284335640Shselasky
1285335640Shselasky		while (token != NULL)
1286335640Shselasky		{
1287335640Shselasky			struct addrinfo hints;
1288335640Shselasky			int retval;
1289335640Shselasky
1290335640Shselasky			addrinfo = NULL;
1291335640Shselasky			memset(&hints, 0, sizeof(struct addrinfo));
1292335640Shselasky			hints.ai_family = PF_UNSPEC;
1293335640Shselasky			hints.ai_socktype = SOCK_STREAM;
1294335640Shselasky
1295356341Scy			retval = getaddrinfo(token, NULL, &hints, &addrinfo);
1296335640Shselasky			if (retval != 0)
1297335640Shselasky			{
1298335640Shselasky				if (errbuf)
1299356341Scy					get_gai_errstring(errbuf, errbuflen,
1300356341Scy					    "Allowed host list error: ",
1301356341Scy					    retval, token, NULL);
1302335640Shselasky
1303356341Scy				/*
1304356341Scy				 * Note that at least one call to getaddrinfo()
1305356341Scy				 * failed.
1306356341Scy				 */
1307356341Scy				getaddrinfo_failed = 1;
1308335640Shselasky
1309335640Shselasky				/* Get next token */
1310335640Shselasky				token = pcap_strtok_r(NULL, sep, &lasts);
1311335640Shselasky				continue;
1312335640Shselasky			}
1313335640Shselasky
1314335640Shselasky			/* ai_next is required to preserve the content of addrinfo, in order to deallocate it properly */
1315335640Shselasky			ai_next = addrinfo;
1316335640Shselasky			while (ai_next)
1317335640Shselasky			{
1318335640Shselasky				if (sock_cmpaddr(from, (struct sockaddr_storage *) ai_next->ai_addr) == 0)
1319335640Shselasky				{
1320335640Shselasky					free(temphostlist);
1321335640Shselasky					freeaddrinfo(addrinfo);
1322335640Shselasky					return 0;
1323335640Shselasky				}
1324335640Shselasky
1325335640Shselasky				/*
1326335640Shselasky				 * If we are here, it means that the current address does not matches
1327335640Shselasky				 * Let's try with the next one in the header chain
1328335640Shselasky				 */
1329335640Shselasky				ai_next = ai_next->ai_next;
1330335640Shselasky			}
1331335640Shselasky
1332335640Shselasky			freeaddrinfo(addrinfo);
1333335640Shselasky			addrinfo = NULL;
1334335640Shselasky
1335335640Shselasky			/* Get next token */
1336335640Shselasky			token = pcap_strtok_r(NULL, sep, &lasts);
1337335640Shselasky		}
1338335640Shselasky
1339335640Shselasky		if (addrinfo)
1340335640Shselasky		{
1341335640Shselasky			freeaddrinfo(addrinfo);
1342335640Shselasky			addrinfo = NULL;
1343335640Shselasky		}
1344335640Shselasky
1345356341Scy		free(temphostlist);
1346335640Shselasky
1347356341Scy		if (getaddrinfo_failed) {
1348356341Scy			/*
1349356341Scy			 * At least one getaddrinfo() call failed;
1350356341Scy			 * treat that as an error, so rpcapd knows
1351356341Scy			 * that it should log it locally as well
1352356341Scy			 * as telling the client about it.
1353356341Scy			 */
1354356341Scy			return -2;
1355356341Scy		} else {
1356356341Scy			/*
1357356341Scy			 * All getaddrinfo() calls succeeded, but
1358356341Scy			 * the host wasn't in the list.
1359356341Scy			 */
1360356341Scy			if (errbuf)
1361356341Scy				pcap_snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused.");
1362356341Scy			return -1;
1363356341Scy		}
1364335640Shselasky	}
1365335640Shselasky
1366335640Shselasky	/* No hostlist, so we have to return 'empty list' */
1367335640Shselasky	return 1;
1368335640Shselasky}
1369335640Shselasky
1370335640Shselasky/*
1371335640Shselasky * \brief Compares two addresses contained into two sockaddr_storage structures.
1372335640Shselasky *
1373335640Shselasky * This function is useful to compare two addresses, given their internal representation,
1374335640Shselasky * i.e. an sockaddr_storage structure.
1375335640Shselasky *
1376335640Shselasky * The two structures do not need to be sockaddr_storage; you can have both 'sockaddr_in' and
1377335640Shselasky * sockaddr_in6, properly acsted in order to be compliant to the function interface.
1378335640Shselasky *
1379335640Shselasky * This function will return '0' if the two addresses matches, '-1' if not.
1380335640Shselasky *
1381335640Shselasky * \param first: a sockaddr_storage structure, (for example the one that is returned by an
1382335640Shselasky * accept() call), containing the first address to compare.
1383335640Shselasky *
1384335640Shselasky * \param second: a sockaddr_storage structure containing the second address to compare.
1385335640Shselasky *
1386335640Shselasky * \return '0' if the addresses are equal, '-1' if they are different.
1387335640Shselasky */
1388335640Shselaskyint sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second)
1389335640Shselasky{
1390335640Shselasky	if (first->ss_family == second->ss_family)
1391335640Shselasky	{
1392335640Shselasky		if (first->ss_family == AF_INET)
1393335640Shselasky		{
1394335640Shselasky			if (memcmp(&(((struct sockaddr_in *) first)->sin_addr),
1395335640Shselasky				&(((struct sockaddr_in *) second)->sin_addr),
1396335640Shselasky				sizeof(struct in_addr)) == 0)
1397335640Shselasky				return 0;
1398335640Shselasky		}
1399335640Shselasky		else /* address family is AF_INET6 */
1400335640Shselasky		{
1401335640Shselasky			if (memcmp(&(((struct sockaddr_in6 *) first)->sin6_addr),
1402335640Shselasky				&(((struct sockaddr_in6 *) second)->sin6_addr),
1403335640Shselasky				sizeof(struct in6_addr)) == 0)
1404335640Shselasky				return 0;
1405335640Shselasky		}
1406335640Shselasky	}
1407335640Shselasky
1408335640Shselasky	return -1;
1409335640Shselasky}
1410335640Shselasky
1411335640Shselasky/*
1412335640Shselasky * \brief It gets the address/port the system picked for this socket (on connected sockets).
1413335640Shselasky *
1414335640Shselasky * It is used to return the address and port the server picked for our socket on the local machine.
1415335640Shselasky * It works only on:
1416335640Shselasky * - connected sockets
1417335640Shselasky * - server sockets
1418335640Shselasky *
1419335640Shselasky * On unconnected client sockets it does not work because the system dynamically chooses a port
1420335640Shselasky * only when the socket calls a send() call.
1421335640Shselasky *
1422335640Shselasky * \param sock: the connected socket currently opened.
1423335640Shselasky *
1424335640Shselasky * \param address: it contains the address that will be returned by the function. This buffer
1425335640Shselasky * must be properly allocated by the user. The address can be either literal or numeric depending
1426335640Shselasky * on the value of 'Flags'.
1427335640Shselasky *
1428335640Shselasky * \param addrlen: the length of the 'address' buffer.
1429335640Shselasky *
1430335640Shselasky * \param port: it contains the port that will be returned by the function. This buffer
1431335640Shselasky * must be properly allocated by the user.
1432335640Shselasky *
1433335640Shselasky * \param portlen: the length of the 'port' buffer.
1434335640Shselasky *
1435335640Shselasky * \param flags: a set of flags (the ones defined into the getnameinfo() standard socket function)
1436335640Shselasky * that determine if the resulting address must be in numeric / literal form, and so on.
1437335640Shselasky *
1438335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
1439335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
1440335640Shselasky * It can be NULL; in this case the error cannot be printed.
1441335640Shselasky *
1442335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
1443335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
1444335640Shselasky *
1445335640Shselasky * \return It returns '-1' if this function succeeds, '0' otherwise.
1446335640Shselasky * The address and port corresponding are returned back in the buffers 'address' and 'port'.
1447335640Shselasky * In any case, the returned strings are '0' terminated.
1448335640Shselasky *
1449335640Shselasky * \warning If the socket is using a connectionless protocol, the address may not be available
1450335640Shselasky * until I/O occurs on the socket.
1451335640Shselasky */
1452335640Shselaskyint sock_getmyinfo(SOCKET sock, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen)
1453335640Shselasky{
1454335640Shselasky	struct sockaddr_storage mysockaddr;
1455335640Shselasky	socklen_t sockaddrlen;
1456335640Shselasky
1457335640Shselasky
1458335640Shselasky	sockaddrlen = sizeof(struct sockaddr_storage);
1459335640Shselasky
1460335640Shselasky	if (getsockname(sock, (struct sockaddr *) &mysockaddr, &sockaddrlen) == -1)
1461335640Shselasky	{
1462356341Scy		sock_geterror("getsockname()", errbuf, errbuflen);
1463335640Shselasky		return 0;
1464335640Shselasky	}
1465335640Shselasky
1466335640Shselasky	/* Returns the numeric address of the host that triggered the error */
1467335640Shselasky	return sock_getascii_addrport(&mysockaddr, address, addrlen, port, portlen, flags, errbuf, errbuflen);
1468335640Shselasky}
1469335640Shselasky
1470335640Shselasky/*
1471335640Shselasky * \brief It retrieves two strings containing the address and the port of a given 'sockaddr' variable.
1472335640Shselasky *
1473335640Shselasky * This function is basically an extended version of the inet_ntop(), which does not exist in
1474335640Shselasky * Winsock because the same result can be obtained by using the getnameinfo().
1475335640Shselasky * However, differently from inet_ntop(), this function is able to return also literal names
1476335640Shselasky * (e.g. 'localhost') dependently from the 'Flags' parameter.
1477335640Shselasky *
1478335640Shselasky * The function accepts a sockaddr_storage variable (which can be returned by several functions
1479335640Shselasky * like bind(), connect(), accept(), and more) and it transforms its content into a 'human'
1480335640Shselasky * form. So, for instance, it is able to translate an hex address (stored in binary form) into
1481335640Shselasky * a standard IPv6 address like "::1".
1482335640Shselasky *
1483335640Shselasky * The behavior of this function depends on the parameters we have in the 'Flags' variable, which
1484335640Shselasky * are the ones allowed in the standard getnameinfo() socket function.
1485335640Shselasky *
1486335640Shselasky * \param sockaddr: a 'sockaddr_in' or 'sockaddr_in6' structure containing the address that
1487335640Shselasky * need to be translated from network form into the presentation form. This structure must be
1488335640Shselasky * zero-ed prior using it, and the address family field must be filled with the proper value.
1489335640Shselasky * The user must cast any 'sockaddr_in' or 'sockaddr_in6' structures to 'sockaddr_storage' before
1490335640Shselasky * calling this function.
1491335640Shselasky *
1492335640Shselasky * \param address: it contains the address that will be returned by the function. This buffer
1493335640Shselasky * must be properly allocated by the user. The address can be either literal or numeric depending
1494335640Shselasky * on the value of 'Flags'.
1495335640Shselasky *
1496335640Shselasky * \param addrlen: the length of the 'address' buffer.
1497335640Shselasky *
1498335640Shselasky * \param port: it contains the port that will be returned by the function. This buffer
1499335640Shselasky * must be properly allocated by the user.
1500335640Shselasky *
1501335640Shselasky * \param portlen: the length of the 'port' buffer.
1502335640Shselasky *
1503335640Shselasky * \param flags: a set of flags (the ones defined into the getnameinfo() standard socket function)
1504335640Shselasky * that determine if the resulting address must be in numeric / literal form, and so on.
1505335640Shselasky *
1506335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
1507335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
1508335640Shselasky * It can be NULL; in this case the error cannot be printed.
1509335640Shselasky *
1510335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
1511335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
1512335640Shselasky *
1513335640Shselasky * \return It returns '-1' if this function succeeds, '0' otherwise.
1514335640Shselasky * The address and port corresponding to the given SockAddr are returned back in the buffers 'address'
1515335640Shselasky * and 'port'.
1516335640Shselasky * In any case, the returned strings are '0' terminated.
1517335640Shselasky */
1518335640Shselaskyint sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen)
1519335640Shselasky{
1520335640Shselasky	socklen_t sockaddrlen;
1521335640Shselasky	int retval;					/* Variable that keeps the return value; */
1522335640Shselasky
1523335640Shselasky	retval = -1;
1524335640Shselasky
1525335640Shselasky#ifdef _WIN32
1526335640Shselasky	if (sockaddr->ss_family == AF_INET)
1527335640Shselasky		sockaddrlen = sizeof(struct sockaddr_in);
1528335640Shselasky	else
1529335640Shselasky		sockaddrlen = sizeof(struct sockaddr_in6);
1530335640Shselasky#else
1531335640Shselasky	sockaddrlen = sizeof(struct sockaddr_storage);
1532335640Shselasky#endif
1533335640Shselasky
1534335640Shselasky	if ((flags & NI_NUMERICHOST) == 0)	/* Check that we want literal names */
1535335640Shselasky	{
1536335640Shselasky		if ((sockaddr->ss_family == AF_INET6) &&
1537335640Shselasky			(memcmp(&((struct sockaddr_in6 *) sockaddr)->sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(struct in6_addr)) == 0))
1538335640Shselasky		{
1539335640Shselasky			if (address)
1540356341Scy				pcap_strlcpy(address, SOCKET_NAME_NULL_DAD, addrlen);
1541335640Shselasky			return retval;
1542335640Shselasky		}
1543335640Shselasky	}
1544335640Shselasky
1545335640Shselasky	if (getnameinfo((struct sockaddr *) sockaddr, sockaddrlen, address, addrlen, port, portlen, flags) != 0)
1546335640Shselasky	{
1547335640Shselasky		/* If the user wants to receive an error message */
1548335640Shselasky		if (errbuf)
1549335640Shselasky		{
1550356341Scy			sock_geterror("getnameinfo()", errbuf, errbuflen);
1551335640Shselasky			errbuf[errbuflen - 1] = 0;
1552335640Shselasky		}
1553335640Shselasky
1554335640Shselasky		if (address)
1555335640Shselasky		{
1556356341Scy			pcap_strlcpy(address, SOCKET_NO_NAME_AVAILABLE, addrlen);
1557335640Shselasky			address[addrlen - 1] = 0;
1558335640Shselasky		}
1559335640Shselasky
1560335640Shselasky		if (port)
1561335640Shselasky		{
1562356341Scy			pcap_strlcpy(port, SOCKET_NO_PORT_AVAILABLE, portlen);
1563335640Shselasky			port[portlen - 1] = 0;
1564335640Shselasky		}
1565335640Shselasky
1566335640Shselasky		retval = 0;
1567335640Shselasky	}
1568335640Shselasky
1569335640Shselasky	return retval;
1570335640Shselasky}
1571335640Shselasky
1572335640Shselasky/*
1573335640Shselasky * \brief It translates an address from the 'presentation' form into the 'network' form.
1574335640Shselasky *
1575335640Shselasky * This function basically replaces inet_pton(), which does not exist in Winsock because
1576335640Shselasky * the same result can be obtained by using the getaddrinfo().
1577335640Shselasky * An additional advantage is that 'Address' can be both a numeric address (e.g. '127.0.0.1',
1578335640Shselasky * like in inet_pton() ) and a literal name (e.g. 'localhost').
1579335640Shselasky *
1580335640Shselasky * This function does the reverse job of sock_getascii_addrport().
1581335640Shselasky *
1582335640Shselasky * \param address: a zero-terminated string which contains the name you have to
1583335640Shselasky * translate. The name can be either literal (e.g. 'localhost') or numeric (e.g. '::1').
1584335640Shselasky *
1585335640Shselasky * \param sockaddr: a user-allocated sockaddr_storage structure which will contains the
1586335640Shselasky * 'network' form of the requested address.
1587335640Shselasky *
1588335640Shselasky * \param addr_family: a constant which can assume the following values:
1589335640Shselasky * - 'AF_INET' if we want to ping an IPv4 host
1590335640Shselasky * - 'AF_INET6' if we want to ping an IPv6 host
1591335640Shselasky * - 'AF_UNSPEC' if we do not have preferences about the protocol used to ping the host
1592335640Shselasky *
1593335640Shselasky * \param errbuf: a pointer to an user-allocated buffer that will contain the complete
1594335640Shselasky * error message. This buffer has to be at least 'errbuflen' in length.
1595335640Shselasky * It can be NULL; in this case the error cannot be printed.
1596335640Shselasky *
1597335640Shselasky * \param errbuflen: length of the buffer that will contains the error. The error message cannot be
1598335640Shselasky * larger than 'errbuflen - 1' because the last char is reserved for the string terminator.
1599335640Shselasky *
1600335640Shselasky * \return '-1' if the translation succeeded, '-2' if there was some non critical error, '0'
1601335640Shselasky * otherwise. In case it fails, the content of the SockAddr variable remains unchanged.
1602335640Shselasky * A 'non critical error' can occur in case the 'Address' is a literal name, which can be mapped
1603335640Shselasky * to several network addresses (e.g. 'foo.bar.com' => '10.2.2.2' and '10.2.2.3'). In this case
1604335640Shselasky * the content of the SockAddr parameter will be the address corresponding to the first mapping.
1605335640Shselasky *
1606335640Shselasky * \warning The sockaddr_storage structure MUST be allocated by the user.
1607335640Shselasky */
1608335640Shselaskyint sock_present2network(const char *address, struct sockaddr_storage *sockaddr, int addr_family, char *errbuf, int errbuflen)
1609335640Shselasky{
1610335640Shselasky	int retval;
1611335640Shselasky	struct addrinfo *addrinfo;
1612335640Shselasky	struct addrinfo hints;
1613335640Shselasky
1614335640Shselasky	memset(&hints, 0, sizeof(hints));
1615335640Shselasky
1616335640Shselasky	hints.ai_family = addr_family;
1617335640Shselasky
1618335640Shselasky	if ((retval = sock_initaddress(address, "22222" /* fake port */, &hints, &addrinfo, errbuf, errbuflen)) == -1)
1619335640Shselasky		return 0;
1620335640Shselasky
1621335640Shselasky	if (addrinfo->ai_family == PF_INET)
1622335640Shselasky		memcpy(sockaddr, addrinfo->ai_addr, sizeof(struct sockaddr_in));
1623335640Shselasky	else
1624335640Shselasky		memcpy(sockaddr, addrinfo->ai_addr, sizeof(struct sockaddr_in6));
1625335640Shselasky
1626335640Shselasky	if (addrinfo->ai_next != NULL)
1627335640Shselasky	{
1628335640Shselasky		freeaddrinfo(addrinfo);
1629335640Shselasky
1630335640Shselasky		if (errbuf)
1631335640Shselasky			pcap_snprintf(errbuf, errbuflen, "More than one socket requested; using the first one returned");
1632335640Shselasky		return -2;
1633335640Shselasky	}
1634335640Shselasky
1635335640Shselasky	freeaddrinfo(addrinfo);
1636335640Shselasky	return -1;
1637335640Shselasky}
1638