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