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