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