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 *
socktoa(const sockaddr_u * sock)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 *
sockporttoa(const sockaddr_u * sock)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
sock_hash(const sockaddr_u * addr)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
sockaddr_masktoprefixlen(const sockaddr_u * psa)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