1132451Sroberto/*
2290001Sglebius * socktoa.c	socktoa(), sockporttoa(), and sock_hash()
3132451Sroberto */
4132451Sroberto
5290001Sglebius#ifdef HAVE_CONFIG_H
6132451Sroberto#include <config.h>
7290001Sglebius#endif
8132451Sroberto
9132451Sroberto#include <sys/types.h>
10290001Sglebius#ifdef HAVE_SYS_SOCKET_H
11132451Sroberto#include <sys/socket.h>
12290001Sglebius#endif
13290001Sglebius#ifdef HAVE_NETINET_IN_H
14132451Sroberto#include <netinet/in.h>
15132451Sroberto#endif
16132451Sroberto
17132451Sroberto#include <stdio.h>
18290001Sglebius#include <arpa/inet.h>
19290001Sglebius#include <isc/result.h>
20290001Sglebius#include <isc/netaddr.h>
21290001Sglebius#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
28290001Sglebius/*
29290001Sglebius * socktoa - return a numeric host name from a sockaddr_storage structure
30290001Sglebius */
31290001Sglebiusconst char *
32132451Srobertosocktoa(
33290001Sglebius	const sockaddr_u *sock
34132451Sroberto	)
35132451Sroberto{
36290001Sglebius	int		saved_errno;
37290001Sglebius	char *		res;
38290001Sglebius	char *		addr;
39290001Sglebius	u_long		scope;
40132451Sroberto
41290001Sglebius	saved_errno = socket_errno();
42290001Sglebius	LIB_GETBUF(res);
43132451Sroberto
44290001Sglebius	if (NULL == sock) {
45290001Sglebius		strlcpy(res, "(null)", LIB_BUFLENGTH);
46290001Sglebius	} else {
47290001Sglebius		switch(AF(sock)) {
48132451Sroberto
49290001Sglebius		case AF_INET:
50290001Sglebius		case AF_UNSPEC:
51290001Sglebius			inet_ntop(AF_INET, PSOCK_ADDR4(sock), res,
52290001Sglebius				  LIB_BUFLENGTH);
53290001Sglebius			break;
54132451Sroberto
55290001Sglebius		case AF_INET6:
56290001Sglebius			inet_ntop(AF_INET6, PSOCK_ADDR6(sock), res,
57290001Sglebius				  LIB_BUFLENGTH);
58290001Sglebius			scope = SCOPE_VAR(sock);
59290001Sglebius			if (0 != scope && !strchr(res, '%')) {
60290001Sglebius				addr = res;
61290001Sglebius				LIB_GETBUF(res);
62290001Sglebius				snprintf(res, LIB_BUFLENGTH, "%s%%%lu",
63290001Sglebius					 addr, scope);
64290001Sglebius				res[LIB_BUFLENGTH - 1] = '\0';
65290001Sglebius			}
66132451Sroberto			break;
67132451Sroberto
68182007Sroberto		default:
69290001Sglebius			snprintf(res, LIB_BUFLENGTH,
70290001Sglebius				 "(socktoa unknown family %d)",
71290001Sglebius				 AF(sock));
72182007Sroberto		}
73132451Sroberto	}
74290001Sglebius	errno = saved_errno;
75290001Sglebius
76290001Sglebius	return res;
77132451Sroberto}
78290001Sglebius
79290001Sglebius
80290001Sglebiusconst char *
81290001Sglebiussockporttoa(
82290001Sglebius	const sockaddr_u *sock
83290001Sglebius	)
84290001Sglebius{
85290001Sglebius	int		saved_errno;
86290001Sglebius	const char *	atext;
87290001Sglebius	char *		buf;
88290001Sglebius
89290001Sglebius	saved_errno = socket_errno();
90290001Sglebius	atext = socktoa(sock);
91290001Sglebius	LIB_GETBUF(buf);
92290001Sglebius	snprintf(buf, LIB_BUFLENGTH,
93290001Sglebius		 (IS_IPV6(sock))
94290001Sglebius		     ? "[%s]:%hu"
95290001Sglebius		     : "%s:%hu",
96290001Sglebius		 atext, SRCPORT(sock));
97290001Sglebius	errno = saved_errno;
98290001Sglebius
99290001Sglebius	return buf;
100290001Sglebius}
101290001Sglebius
102290001Sglebius
103290001Sglebius/*
104290001Sglebius * sock_hash - hash a sockaddr_u structure
105290001Sglebius */
106290001Sglebiusu_short
107290001Sglebiussock_hash(
108290001Sglebius	const sockaddr_u *addr
109290001Sglebius	)
110290001Sglebius{
111290001Sglebius	u_int hashVal;
112290001Sglebius	u_int j;
113290001Sglebius	size_t len;
114290001Sglebius	const u_char *pch;
115290001Sglebius
116290001Sglebius	hashVal = 0;
117290001Sglebius	len = 0;
118290001Sglebius
119290001Sglebius	/*
120290001Sglebius	 * We can't just hash the whole thing because there are hidden
121290001Sglebius	 * fields in sockaddr_in6 that might be filled in by recvfrom(),
122290001Sglebius	 * so just use the family, port and address.
123290001Sglebius	 */
124290001Sglebius	pch = (const void *)&AF(addr);
125290001Sglebius	hashVal = 37 * hashVal + *pch;
126290001Sglebius	if (sizeof(AF(addr)) > 1) {
127290001Sglebius		pch++;
128290001Sglebius		hashVal = 37 * hashVal + *pch;
129290001Sglebius	}
130290001Sglebius	switch(AF(addr)) {
131290001Sglebius	case AF_INET:
132290001Sglebius		pch = (const void *)&SOCK_ADDR4(addr);
133290001Sglebius		len = sizeof(SOCK_ADDR4(addr));
134290001Sglebius		break;
135290001Sglebius
136290001Sglebius	case AF_INET6:
137290001Sglebius		pch = (const void *)&SOCK_ADDR6(addr);
138290001Sglebius		len = sizeof(SOCK_ADDR6(addr));
139290001Sglebius		break;
140290001Sglebius	}
141290001Sglebius
142290001Sglebius	for (j = 0; j < len ; j++)
143290001Sglebius		hashVal = 37 * hashVal + pch[j];
144290001Sglebius
145290001Sglebius	return (u_short)(hashVal & USHRT_MAX);
146290001Sglebius}
147290001Sglebius
148290001Sglebius
149290001Sglebiusint
150290001Sglebiussockaddr_masktoprefixlen(
151290001Sglebius	const sockaddr_u *	psa
152290001Sglebius	)
153290001Sglebius{
154290001Sglebius	isc_netaddr_t	isc_na;
155290001Sglebius	isc_sockaddr_t	isc_sa;
156290001Sglebius	u_int		pfxlen;
157290001Sglebius	isc_result_t	result;
158290001Sglebius	int		rc;
159290001Sglebius
160290001Sglebius	ZERO(isc_sa);
161290001Sglebius	memcpy(&isc_sa.type, psa,
162290001Sglebius	       min(sizeof(isc_sa.type), sizeof(*psa)));
163290001Sglebius	isc_netaddr_fromsockaddr(&isc_na, &isc_sa);
164290001Sglebius	result = isc_netaddr_masktoprefixlen(&isc_na, &pfxlen);
165290001Sglebius	rc = (ISC_R_SUCCESS == result)
166290001Sglebius		 ? (int)pfxlen
167290001Sglebius		 : -1;
168290001Sglebius
169290001Sglebius	return rc;
170290001Sglebius}
171