1132451Sroberto/*
2285612Sdelphij * socktoa.c	socktoa(), sockporttoa(), and sock_hash()
3132451Sroberto */
4132451Sroberto
5285612Sdelphij#ifdef HAVE_CONFIG_H
6132451Sroberto#include <config.h>
7285612Sdelphij#endif
8132451Sroberto
9132451Sroberto#include <sys/types.h>
10285612Sdelphij#ifdef HAVE_SYS_SOCKET_H
11132451Sroberto#include <sys/socket.h>
12285612Sdelphij#endif
13285612Sdelphij#ifdef HAVE_NETINET_IN_H
14132451Sroberto#include <netinet/in.h>
15132451Sroberto#endif
16132451Sroberto
17132451Sroberto#include <stdio.h>
18285612Sdelphij#include <arpa/inet.h>
19285612Sdelphij#include <isc/result.h>
20285612Sdelphij#include <isc/netaddr.h>
21285612Sdelphij#include <isc/sockaddr.h>
22132451Sroberto
23132451Sroberto#include "ntp_fp.h"
24132451Sroberto#include "lib_strbuf.h"
25132451Sroberto#include "ntp_stdlib.h"
26132451Sroberto#include "ntp.h"
27132451Sroberto
28285612Sdelphij/*
29285612Sdelphij * socktoa - return a numeric host name from a sockaddr_storage structure
30285612Sdelphij */
31285612Sdelphijconst char *
32132451Srobertosocktoa(
33285612Sdelphij	const sockaddr_u *sock
34132451Sroberto	)
35132451Sroberto{
36285612Sdelphij	int		saved_errno;
37285612Sdelphij	char *		res;
38285612Sdelphij	char *		addr;
39285612Sdelphij	u_long		scope;
40132451Sroberto
41285612Sdelphij	saved_errno = socket_errno();
42285612Sdelphij	LIB_GETBUF(res);
43132451Sroberto
44285612Sdelphij	if (NULL == sock) {
45285612Sdelphij		strlcpy(res, "(null)", LIB_BUFLENGTH);
46285612Sdelphij	} else {
47285612Sdelphij		switch(AF(sock)) {
48132451Sroberto
49285612Sdelphij		case AF_INET:
50285612Sdelphij		case AF_UNSPEC:
51285612Sdelphij			inet_ntop(AF_INET, PSOCK_ADDR4(sock), res,
52285612Sdelphij				  LIB_BUFLENGTH);
53285612Sdelphij			break;
54132451Sroberto
55285612Sdelphij		case AF_INET6:
56285612Sdelphij			inet_ntop(AF_INET6, PSOCK_ADDR6(sock), res,
57285612Sdelphij				  LIB_BUFLENGTH);
58285612Sdelphij			scope = SCOPE_VAR(sock);
59285612Sdelphij			if (0 != scope && !strchr(res, '%')) {
60285612Sdelphij				addr = res;
61285612Sdelphij				LIB_GETBUF(res);
62285612Sdelphij				snprintf(res, LIB_BUFLENGTH, "%s%%%lu",
63285612Sdelphij					 addr, scope);
64285612Sdelphij				res[LIB_BUFLENGTH - 1] = '\0';
65285612Sdelphij			}
66132451Sroberto			break;
67132451Sroberto
68182007Sroberto		default:
69285612Sdelphij			snprintf(res, LIB_BUFLENGTH,
70285612Sdelphij				 "(socktoa unknown family %d)",
71285612Sdelphij				 AF(sock));
72182007Sroberto		}
73132451Sroberto	}
74285612Sdelphij	errno = saved_errno;
75285612Sdelphij
76285612Sdelphij	return res;
77132451Sroberto}
78285612Sdelphij
79285612Sdelphij
80285612Sdelphijconst char *
81285612Sdelphijsockporttoa(
82285612Sdelphij	const sockaddr_u *sock
83285612Sdelphij	)
84285612Sdelphij{
85285612Sdelphij	int		saved_errno;
86285612Sdelphij	const char *	atext;
87285612Sdelphij	char *		buf;
88285612Sdelphij
89285612Sdelphij	saved_errno = socket_errno();
90285612Sdelphij	atext = socktoa(sock);
91285612Sdelphij	LIB_GETBUF(buf);
92285612Sdelphij	snprintf(buf, LIB_BUFLENGTH,
93285612Sdelphij		 (IS_IPV6(sock))
94285612Sdelphij		     ? "[%s]:%hu"
95285612Sdelphij		     : "%s:%hu",
96285612Sdelphij		 atext, SRCPORT(sock));
97285612Sdelphij	errno = saved_errno;
98285612Sdelphij
99285612Sdelphij	return buf;
100285612Sdelphij}
101285612Sdelphij
102285612Sdelphij
103285612Sdelphij/*
104285612Sdelphij * sock_hash - hash a sockaddr_u structure
105285612Sdelphij */
106285612Sdelphiju_short
107285612Sdelphijsock_hash(
108285612Sdelphij	const sockaddr_u *addr
109285612Sdelphij	)
110285612Sdelphij{
111285612Sdelphij	u_int hashVal;
112285612Sdelphij	u_int j;
113285612Sdelphij	size_t len;
114285612Sdelphij	const u_char *pch;
115285612Sdelphij
116285612Sdelphij	hashVal = 0;
117285612Sdelphij	len = 0;
118285612Sdelphij
119285612Sdelphij	/*
120285612Sdelphij	 * We can't just hash the whole thing because there are hidden
121285612Sdelphij	 * fields in sockaddr_in6 that might be filled in by recvfrom(),
122285612Sdelphij	 * so just use the family, port and address.
123285612Sdelphij	 */
124285612Sdelphij	pch = (const void *)&AF(addr);
125285612Sdelphij	hashVal = 37 * hashVal + *pch;
126285612Sdelphij	if (sizeof(AF(addr)) > 1) {
127285612Sdelphij		pch++;
128285612Sdelphij		hashVal = 37 * hashVal + *pch;
129285612Sdelphij	}
130285612Sdelphij	switch(AF(addr)) {
131285612Sdelphij	case AF_INET:
132285612Sdelphij		pch = (const void *)&SOCK_ADDR4(addr);
133285612Sdelphij		len = sizeof(SOCK_ADDR4(addr));
134285612Sdelphij		break;
135285612Sdelphij
136285612Sdelphij	case AF_INET6:
137285612Sdelphij		pch = (const void *)&SOCK_ADDR6(addr);
138285612Sdelphij		len = sizeof(SOCK_ADDR6(addr));
139285612Sdelphij		break;
140285612Sdelphij	}
141285612Sdelphij
142285612Sdelphij	for (j = 0; j < len ; j++)
143285612Sdelphij		hashVal = 37 * hashVal + pch[j];
144285612Sdelphij
145285612Sdelphij	return (u_short)(hashVal & USHRT_MAX);
146285612Sdelphij}
147285612Sdelphij
148285612Sdelphij
149285612Sdelphijint
150285612Sdelphijsockaddr_masktoprefixlen(
151285612Sdelphij	const sockaddr_u *	psa
152285612Sdelphij	)
153285612Sdelphij{
154285612Sdelphij	isc_netaddr_t	isc_na;
155285612Sdelphij	isc_sockaddr_t	isc_sa;
156285612Sdelphij	u_int		pfxlen;
157285612Sdelphij	isc_result_t	result;
158285612Sdelphij	int		rc;
159285612Sdelphij
160285612Sdelphij	ZERO(isc_sa);
161285612Sdelphij	memcpy(&isc_sa.type, psa,
162285612Sdelphij	       min(sizeof(isc_sa.type), sizeof(*psa)));
163285612Sdelphij	isc_netaddr_fromsockaddr(&isc_na, &isc_sa);
164285612Sdelphij	result = isc_netaddr_masktoprefixlen(&isc_na, &pfxlen);
165285612Sdelphij	rc = (ISC_R_SUCCESS == result)
166285612Sdelphij		 ? (int)pfxlen
167285612Sdelphij		 : -1;
168285612Sdelphij
169285612Sdelphij	return rc;
170285612Sdelphij}
171