1 | /* |
---|
2 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
---|
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
---|
4 | * All rights reserved |
---|
5 | * Functions for returning the canonical host name of the remote site. |
---|
6 | * |
---|
7 | * As far as I am concerned, the code I have written for this software |
---|
8 | * can be used freely for any purpose. Any derived versions of this |
---|
9 | * software must be clearly marked as such, and if the derived work is |
---|
10 | * incompatible with the protocol description in the RFC file, it must be |
---|
11 | * called by a name other than "ssh" or "Secure Shell". |
---|
12 | */ |
---|
13 | |
---|
14 | #include "includes.h" |
---|
15 | RCSID("$OpenBSD: canohost.c,v 1.34 2002/09/23 20:46:27 stevesk Exp $"); |
---|
16 | |
---|
17 | #include "packet.h" |
---|
18 | #include "xmalloc.h" |
---|
19 | #include "log.h" |
---|
20 | #include "canohost.h" |
---|
21 | |
---|
22 | static void check_ip_options(int, char *); |
---|
23 | |
---|
24 | /* |
---|
25 | * Return the canonical name of the host at the other end of the socket. The |
---|
26 | * caller should free the returned string with xfree. |
---|
27 | */ |
---|
28 | |
---|
29 | static char * |
---|
30 | get_remote_hostname(int socket, int verify_reverse_mapping) |
---|
31 | { |
---|
32 | struct sockaddr_storage from; |
---|
33 | int i; |
---|
34 | socklen_t fromlen; |
---|
35 | struct addrinfo hints, *ai, *aitop; |
---|
36 | char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST]; |
---|
37 | |
---|
38 | /* Get IP address of client. */ |
---|
39 | fromlen = sizeof(from); |
---|
40 | memset(&from, 0, sizeof(from)); |
---|
41 | if (getpeername(socket, (struct sockaddr *) &from, &fromlen) < 0) { |
---|
42 | debug("getpeername failed: %.100s", strerror(errno)); |
---|
43 | fatal_cleanup(); |
---|
44 | } |
---|
45 | #ifdef IPV4_IN_IPV6 |
---|
46 | if (from.ss_family == AF_INET6) { |
---|
47 | struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from; |
---|
48 | |
---|
49 | /* Detect IPv4 in IPv6 mapped address and convert it to */ |
---|
50 | /* plain (AF_INET) IPv4 address */ |
---|
51 | if (IN6_IS_ADDR_V4MAPPED(&from6->sin6_addr)) { |
---|
52 | struct sockaddr_in *from4 = (struct sockaddr_in *)&from; |
---|
53 | struct in_addr addr; |
---|
54 | u_int16_t port; |
---|
55 | |
---|
56 | memcpy(&addr, ((char *)&from6->sin6_addr) + 12, sizeof(addr)); |
---|
57 | port = from6->sin6_port; |
---|
58 | |
---|
59 | memset(&from, 0, sizeof(from)); |
---|
60 | |
---|
61 | from4->sin_family = AF_INET; |
---|
62 | memcpy(&from4->sin_addr, &addr, sizeof(addr)); |
---|
63 | from4->sin_port = port; |
---|
64 | } |
---|
65 | } |
---|
66 | #endif |
---|
67 | |
---|
68 | if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), |
---|
69 | NULL, 0, NI_NUMERICHOST) != 0) |
---|
70 | fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed"); |
---|
71 | |
---|
72 | if (from.ss_family == AF_INET) |
---|
73 | check_ip_options(socket, ntop); |
---|
74 | |
---|
75 | debug3("Trying to reverse map address %.100s.", ntop); |
---|
76 | /* Map the IP address to a host name. */ |
---|
77 | if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), |
---|
78 | NULL, 0, NI_NAMEREQD) != 0) { |
---|
79 | /* Host name not found. Use ip address. */ |
---|
80 | #if 0 |
---|
81 | log("Could not reverse map address %.100s.", ntop); |
---|
82 | #endif |
---|
83 | return xstrdup(ntop); |
---|
84 | } |
---|
85 | |
---|
86 | /* Got host name. */ |
---|
87 | name[sizeof(name) - 1] = '\0'; |
---|
88 | /* |
---|
89 | * Convert it to all lowercase (which is expected by the rest |
---|
90 | * of this software). |
---|
91 | */ |
---|
92 | for (i = 0; name[i]; i++) |
---|
93 | if (isupper(name[i])) |
---|
94 | name[i] = tolower(name[i]); |
---|
95 | |
---|
96 | if (!verify_reverse_mapping) |
---|
97 | return xstrdup(name); |
---|
98 | /* |
---|
99 | * Map it back to an IP address and check that the given |
---|
100 | * address actually is an address of this host. This is |
---|
101 | * necessary because anyone with access to a name server can |
---|
102 | * define arbitrary names for an IP address. Mapping from |
---|
103 | * name to IP address can be trusted better (but can still be |
---|
104 | * fooled if the intruder has access to the name server of |
---|
105 | * the domain). |
---|
106 | */ |
---|
107 | memset(&hints, 0, sizeof(hints)); |
---|
108 | hints.ai_family = from.ss_family; |
---|
109 | hints.ai_socktype = SOCK_STREAM; |
---|
110 | if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { |
---|
111 | log("reverse mapping checking getaddrinfo for %.700s " |
---|
112 | "failed - POSSIBLE BREAKIN ATTEMPT!", name); |
---|
113 | return xstrdup(ntop); |
---|
114 | } |
---|
115 | /* Look for the address from the list of addresses. */ |
---|
116 | for (ai = aitop; ai; ai = ai->ai_next) { |
---|
117 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, |
---|
118 | sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && |
---|
119 | (strcmp(ntop, ntop2) == 0)) |
---|
120 | break; |
---|
121 | } |
---|
122 | freeaddrinfo(aitop); |
---|
123 | /* If we reached the end of the list, the address was not there. */ |
---|
124 | if (!ai) { |
---|
125 | /* Address not found for the host name. */ |
---|
126 | log("Address %.100s maps to %.600s, but this does not " |
---|
127 | "map back to the address - POSSIBLE BREAKIN ATTEMPT!", |
---|
128 | ntop, name); |
---|
129 | return xstrdup(ntop); |
---|
130 | } |
---|
131 | return xstrdup(name); |
---|
132 | } |
---|
133 | |
---|
134 | /* |
---|
135 | * If IP options are supported, make sure there are none (log and |
---|
136 | * disconnect them if any are found). Basically we are worried about |
---|
137 | * source routing; it can be used to pretend you are somebody |
---|
138 | * (ip-address) you are not. That itself may be "almost acceptable" |
---|
139 | * under certain circumstances, but rhosts autentication is useless |
---|
140 | * if source routing is accepted. Notice also that if we just dropped |
---|
141 | * source routing here, the other side could use IP spoofing to do |
---|
142 | * rest of the interaction and could still bypass security. So we |
---|
143 | * exit here if we detect any IP options. |
---|
144 | */ |
---|
145 | /* IPv4 only */ |
---|
146 | static void |
---|
147 | check_ip_options(int socket, char *ipaddr) |
---|
148 | { |
---|
149 | u_char options[200]; |
---|
150 | char text[sizeof(options) * 3 + 1]; |
---|
151 | socklen_t option_size; |
---|
152 | int i, ipproto; |
---|
153 | struct protoent *ip; |
---|
154 | |
---|
155 | if ((ip = getprotobyname("ip")) != NULL) |
---|
156 | ipproto = ip->p_proto; |
---|
157 | else |
---|
158 | ipproto = IPPROTO_IP; |
---|
159 | option_size = sizeof(options); |
---|
160 | if (getsockopt(socket, ipproto, IP_OPTIONS, options, |
---|
161 | &option_size) >= 0 && option_size != 0) { |
---|
162 | text[0] = '\0'; |
---|
163 | for (i = 0; i < option_size; i++) |
---|
164 | snprintf(text + i*3, sizeof(text) - i*3, |
---|
165 | " %2.2x", options[i]); |
---|
166 | log("Connection from %.100s with IP options:%.800s", |
---|
167 | ipaddr, text); |
---|
168 | packet_disconnect("Connection from %.100s with IP options:%.800s", |
---|
169 | ipaddr, text); |
---|
170 | } |
---|
171 | } |
---|
172 | |
---|
173 | /* |
---|
174 | * Return the canonical name of the host in the other side of the current |
---|
175 | * connection. The host name is cached, so it is efficient to call this |
---|
176 | * several times. |
---|
177 | */ |
---|
178 | |
---|
179 | const char * |
---|
180 | get_canonical_hostname(int verify_reverse_mapping) |
---|
181 | { |
---|
182 | static char *canonical_host_name = NULL; |
---|
183 | static int verify_reverse_mapping_done = 0; |
---|
184 | |
---|
185 | /* Check if we have previously retrieved name with same option. */ |
---|
186 | if (canonical_host_name != NULL) { |
---|
187 | if (verify_reverse_mapping_done != verify_reverse_mapping) |
---|
188 | xfree(canonical_host_name); |
---|
189 | else |
---|
190 | return canonical_host_name; |
---|
191 | } |
---|
192 | |
---|
193 | /* Get the real hostname if socket; otherwise return UNKNOWN. */ |
---|
194 | if (packet_connection_is_on_socket()) |
---|
195 | canonical_host_name = get_remote_hostname( |
---|
196 | packet_get_connection_in(), verify_reverse_mapping); |
---|
197 | else |
---|
198 | canonical_host_name = xstrdup("UNKNOWN"); |
---|
199 | |
---|
200 | verify_reverse_mapping_done = verify_reverse_mapping; |
---|
201 | return canonical_host_name; |
---|
202 | } |
---|
203 | |
---|
204 | /* |
---|
205 | * Returns the remote IP-address of socket as a string. The returned |
---|
206 | * string must be freed. |
---|
207 | */ |
---|
208 | static char * |
---|
209 | get_socket_address(int socket, int remote, int flags) |
---|
210 | { |
---|
211 | struct sockaddr_storage addr; |
---|
212 | socklen_t addrlen; |
---|
213 | char ntop[NI_MAXHOST]; |
---|
214 | |
---|
215 | /* Get IP address of client. */ |
---|
216 | addrlen = sizeof(addr); |
---|
217 | memset(&addr, 0, sizeof(addr)); |
---|
218 | |
---|
219 | if (remote) { |
---|
220 | if (getpeername(socket, (struct sockaddr *)&addr, &addrlen) |
---|
221 | < 0) |
---|
222 | return NULL; |
---|
223 | } else { |
---|
224 | if (getsockname(socket, (struct sockaddr *)&addr, &addrlen) |
---|
225 | < 0) |
---|
226 | return NULL; |
---|
227 | } |
---|
228 | /* Get the address in ascii. */ |
---|
229 | if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop), |
---|
230 | NULL, 0, flags) != 0) { |
---|
231 | error("get_socket_ipaddr: getnameinfo %d failed", flags); |
---|
232 | return NULL; |
---|
233 | } |
---|
234 | return xstrdup(ntop); |
---|
235 | } |
---|
236 | |
---|
237 | char * |
---|
238 | get_peer_ipaddr(int socket) |
---|
239 | { |
---|
240 | char *p; |
---|
241 | |
---|
242 | if ((p = get_socket_address(socket, 1, NI_NUMERICHOST)) != NULL) |
---|
243 | return p; |
---|
244 | return xstrdup("UNKNOWN"); |
---|
245 | } |
---|
246 | |
---|
247 | char * |
---|
248 | get_local_ipaddr(int socket) |
---|
249 | { |
---|
250 | char *p; |
---|
251 | |
---|
252 | if ((p = get_socket_address(socket, 0, NI_NUMERICHOST)) != NULL) |
---|
253 | return p; |
---|
254 | return xstrdup("UNKNOWN"); |
---|
255 | } |
---|
256 | |
---|
257 | char * |
---|
258 | get_local_name(int socket) |
---|
259 | { |
---|
260 | return get_socket_address(socket, 0, NI_NAMEREQD); |
---|
261 | } |
---|
262 | |
---|
263 | /* |
---|
264 | * Returns the IP-address of the remote host as a string. The returned |
---|
265 | * string must not be freed. |
---|
266 | */ |
---|
267 | |
---|
268 | const char * |
---|
269 | get_remote_ipaddr(void) |
---|
270 | { |
---|
271 | static char *canonical_host_ip = NULL; |
---|
272 | |
---|
273 | /* Check whether we have cached the ipaddr. */ |
---|
274 | if (canonical_host_ip == NULL) { |
---|
275 | if (packet_connection_is_on_socket()) { |
---|
276 | canonical_host_ip = |
---|
277 | get_peer_ipaddr(packet_get_connection_in()); |
---|
278 | if (canonical_host_ip == NULL) |
---|
279 | fatal_cleanup(); |
---|
280 | } else { |
---|
281 | /* If not on socket, return UNKNOWN. */ |
---|
282 | canonical_host_ip = xstrdup("UNKNOWN"); |
---|
283 | } |
---|
284 | } |
---|
285 | return canonical_host_ip; |
---|
286 | } |
---|
287 | |
---|
288 | const char * |
---|
289 | get_remote_name_or_ip(u_int utmp_len, int verify_reverse_mapping) |
---|
290 | { |
---|
291 | static const char *remote = ""; |
---|
292 | if (utmp_len > 0) |
---|
293 | remote = get_canonical_hostname(verify_reverse_mapping); |
---|
294 | if (utmp_len == 0 || strlen(remote) > utmp_len) |
---|
295 | remote = get_remote_ipaddr(); |
---|
296 | return remote; |
---|
297 | } |
---|
298 | |
---|
299 | /* Returns the local/remote port for the socket. */ |
---|
300 | |
---|
301 | static int |
---|
302 | get_sock_port(int sock, int local) |
---|
303 | { |
---|
304 | struct sockaddr_storage from; |
---|
305 | socklen_t fromlen; |
---|
306 | char strport[NI_MAXSERV]; |
---|
307 | |
---|
308 | /* Get IP address of client. */ |
---|
309 | fromlen = sizeof(from); |
---|
310 | memset(&from, 0, sizeof(from)); |
---|
311 | if (local) { |
---|
312 | if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) { |
---|
313 | error("getsockname failed: %.100s", strerror(errno)); |
---|
314 | return 0; |
---|
315 | } |
---|
316 | } else { |
---|
317 | if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) { |
---|
318 | debug("getpeername failed: %.100s", strerror(errno)); |
---|
319 | fatal_cleanup(); |
---|
320 | } |
---|
321 | } |
---|
322 | /* Return port number. */ |
---|
323 | if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, |
---|
324 | strport, sizeof(strport), NI_NUMERICSERV) != 0) |
---|
325 | fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed"); |
---|
326 | return atoi(strport); |
---|
327 | } |
---|
328 | |
---|
329 | /* Returns remote/local port number for the current connection. */ |
---|
330 | |
---|
331 | static int |
---|
332 | get_port(int local) |
---|
333 | { |
---|
334 | /* |
---|
335 | * If the connection is not a socket, return 65535. This is |
---|
336 | * intentionally chosen to be an unprivileged port number. |
---|
337 | */ |
---|
338 | if (!packet_connection_is_on_socket()) |
---|
339 | return 65535; |
---|
340 | |
---|
341 | /* Get socket and return the port number. */ |
---|
342 | return get_sock_port(packet_get_connection_in(), local); |
---|
343 | } |
---|
344 | |
---|
345 | int |
---|
346 | get_peer_port(int sock) |
---|
347 | { |
---|
348 | return get_sock_port(sock, 0); |
---|
349 | } |
---|
350 | |
---|
351 | int |
---|
352 | get_remote_port(void) |
---|
353 | { |
---|
354 | return get_port(0); |
---|
355 | } |
---|
356 | |
---|
357 | int |
---|
358 | get_local_port(void) |
---|
359 | { |
---|
360 | return get_port(1); |
---|
361 | } |
---|