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