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