1/*
2 * socktoa.c	socktoa(), sockporttoa(), and sock_hash()
3 */
4
5#ifdef HAVE_CONFIG_H
6#include <config.h>
7#endif
8
9#include <sys/types.h>
10#ifdef HAVE_SYS_SOCKET_H
11#include <sys/socket.h>
12#endif
13#ifdef HAVE_NETINET_IN_H
14#include <netinet/in.h>
15#endif
16
17#include <stdio.h>
18#include <arpa/inet.h>
19#include <isc/result.h>
20#include <isc/netaddr.h>
21#include <isc/sockaddr.h>
22
23#include "ntp_fp.h"
24#include "ntp_stdlib.h"
25#include "ntp.h"
26
27/*
28 * socktoa - return a numeric host name from a sockaddr_storage structure
29 */
30const char *
31socktoa(
32	const sockaddr_u *sock
33	)
34{
35	int		saved_errno;
36	char *		res;
37	char *		addr;
38	u_long		scope;
39
40	saved_errno = socket_errno();
41	LIB_GETBUF(res);
42
43	if (NULL == sock) {
44		strlcpy(res, "(null)", LIB_BUFLENGTH);
45	} else {
46		switch(AF(sock)) {
47
48		case AF_INET:
49		case AF_UNSPEC:
50			inet_ntop(AF_INET, PSOCK_ADDR4(sock), res,
51				  LIB_BUFLENGTH);
52			break;
53
54		case AF_INET6:
55			inet_ntop(AF_INET6, PSOCK_ADDR6(sock), res,
56				  LIB_BUFLENGTH);
57			scope = SCOPE_VAR(sock);
58			if (0 != scope && !strchr(res, '%')) {
59				addr = res;
60				LIB_GETBUF(res);
61				snprintf(res, LIB_BUFLENGTH, "%s%%%lu",
62					 addr, scope);
63				res[LIB_BUFLENGTH - 1] = '\0';
64			}
65			break;
66
67		default:
68			snprintf(res, LIB_BUFLENGTH,
69				 "(socktoa unknown family %d)",
70				 AF(sock));
71		}
72	}
73	errno = saved_errno;
74
75	return res;
76}
77
78
79const char *
80sockporttoa(
81	const sockaddr_u *sock
82	)
83{
84	int		saved_errno;
85	const char *	atext;
86	char *		buf;
87
88	saved_errno = socket_errno();
89	atext = socktoa(sock);
90	LIB_GETBUF(buf);
91	snprintf(buf, LIB_BUFLENGTH,
92		 (IS_IPV6(sock))
93		     ? "[%s]:%hu"
94		     : "%s:%hu",
95		 atext, SRCPORT(sock));
96	errno = saved_errno;
97
98	return buf;
99}
100
101
102/*
103 * sock_hash - hash a sockaddr_u structure
104 */
105u_short
106sock_hash(
107	const sockaddr_u *addr
108	)
109{
110	u_int hashVal;
111	u_int j;
112	size_t len;
113	const u_char *pch;
114
115	hashVal = 0;
116	len = 0;
117
118	/*
119	 * We can't just hash the whole thing because there are hidden
120	 * fields in sockaddr_in6 that might be filled in by recvfrom(),
121	 * so just use the family and address.
122	 */
123	pch = (const void *)&AF(addr);
124	hashVal = 37 * hashVal + *pch;
125	if (sizeof(AF(addr)) > 1) {
126		pch++;
127		hashVal = 37 * hashVal + *pch;
128	}
129	switch(AF(addr)) {
130	case AF_INET:
131		pch = (const void *)&SOCK_ADDR4(addr);
132		len = sizeof(SOCK_ADDR4(addr));
133		break;
134
135	case AF_INET6:
136		pch = (const void *)&SOCK_ADDR6(addr);
137		len = sizeof(SOCK_ADDR6(addr));
138		break;
139	}
140
141	for (j = 0; j < len ; j++)
142		hashVal = 37 * hashVal + pch[j];
143
144	return (u_short)(hashVal & USHRT_MAX);
145}
146
147
148int
149sockaddr_masktoprefixlen(
150	const sockaddr_u *	psa
151	)
152{
153	isc_netaddr_t	isc_na;
154	isc_sockaddr_t	isc_sa;
155	u_int		pfxlen;
156	isc_result_t	result;
157	int		rc;
158
159	ZERO(isc_sa);
160	memcpy(&isc_sa.type, psa,
161	       min(sizeof(isc_sa.type), sizeof(*psa)));
162	isc_netaddr_fromsockaddr(&isc_na, &isc_sa);
163	result = isc_netaddr_masktoprefixlen(&isc_na, &pfxlen);
164	rc = (ISC_R_SUCCESS == result)
165		 ? (int)pfxlen
166		 : -1;
167
168	return rc;
169}
170