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