xref: /freebsd/contrib/ntp/libntp/socktoa.c (revision c5c02a131a0e2ef52771e683269bc8778fe511f3)
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  */
30 const char *
31 socktoa(
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 
79 const char *
80 sockporttoa(
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  */
105 u_short
106 sock_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 
148 int
149 sockaddr_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