xref: /titanic_44/usr/src/cmd/ssh/libssh/common/canohost.c (revision 55553f719b521a0bb4deab6efc944cd30c1a56aa)
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  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
15  * Use is subject to license terms.
16  */
17 
18 #include "includes.h"
19 RCSID("$OpenBSD: canohost.c,v 1.34 2002/09/23 20:46:27 stevesk Exp $");
20 
21 #pragma ident	"%Z%%M%	%I%	%E% SMI"
22 
23 #include "packet.h"
24 #include "xmalloc.h"
25 #include "log.h"
26 #include "canohost.h"
27 
28 static const char *inet_ntop_native(int af, const void *src,
29 	char *dst, size_t size);
30 
31 
32 /*
33  * Return the canonical name of the host at the other end of the socket. The
34  * caller should free the returned string with xfree.
35  */
36 
37 static char *
38 get_remote_hostname(int socket, int verify_reverse_mapping)
39 {
40 	struct sockaddr_storage from;
41 	int i, res;
42 	socklen_t fromlen;
43 	struct addrinfo hints, *ai, *aitop;
44 	char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
45 
46 	/* Get IP address of client. */
47 	fromlen = sizeof(from);
48 	memset(&from, 0, sizeof(from));
49 	if (getpeername(socket, (struct sockaddr *) &from, &fromlen) < 0) {
50 		debug("getpeername failed: %.100s", strerror(errno));
51 		fatal_cleanup();
52 	}
53 
54 	if ((res = getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
55 	    NULL, 0, NI_NUMERICHOST)) != 0)
56 		fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed: %d", res);
57 
58 #ifdef IPV4_IN_IPV6
59 	if (from.ss_family == AF_INET6) {
60 		struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from;
61 
62 		(void) inet_ntop_native(from.ss_family,
63 				from6->sin6_addr.s6_addr,
64 				ntop, sizeof(ntop));
65 	}
66 #endif /* IPV4_IN_IPV6 */
67 
68 	debug3("Trying to reverse map address %.100s.", ntop);
69 	/* Map the IP address to a host name. */
70 	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
71 	    NULL, 0, NI_NAMEREQD) != 0) {
72 		/* Host name not found.  Use ip address. */
73 #if 0
74 		log("Could not reverse map address %.100s.", ntop);
75 #endif
76 		return xstrdup(ntop);
77 	}
78 
79 	/* Got host name. */
80 	name[sizeof(name) - 1] = '\0';
81 	/*
82 	 * Convert it to all lowercase (which is expected by the rest
83 	 * of this software).
84 	 */
85 	for (i = 0; name[i]; i++)
86 		if (isupper(name[i]))
87 			name[i] = tolower(name[i]);
88 
89 	if (!verify_reverse_mapping)
90 		return xstrdup(name);
91 	/*
92 	 * Map it back to an IP address and check that the given
93 	 * address actually is an address of this host.  This is
94 	 * necessary because anyone with access to a name server can
95 	 * define arbitrary names for an IP address. Mapping from
96 	 * name to IP address can be trusted better (but can still be
97 	 * fooled if the intruder has access to the name server of
98 	 * the domain).
99 	 */
100 	memset(&hints, 0, sizeof(hints));
101 	hints.ai_family = from.ss_family;
102 	hints.ai_socktype = SOCK_STREAM;
103 	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
104 		log("reverse mapping checking getaddrinfo for %.700s "
105 		    "failed - POSSIBLE BREAKIN ATTEMPT!", name);
106 		return xstrdup(ntop);
107 	}
108 	/* Look for the address from the list of addresses. */
109 	for (ai = aitop; ai; ai = ai->ai_next) {
110 		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
111 		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
112 		    (strcmp(ntop, ntop2) == 0))
113 				break;
114 	}
115 	freeaddrinfo(aitop);
116 	/* If we reached the end of the list, the address was not there. */
117 	if (!ai) {
118 		/* Address not found for the host name. */
119 		log("Address %.100s maps to %.600s, but this does not "
120 		    "map back to the address - POSSIBLE BREAKIN ATTEMPT!",
121 		    ntop, name);
122 		return xstrdup(ntop);
123 	}
124 	return xstrdup(name);
125 }
126 
127 /*
128  * Return the canonical name of the host in the other side of the current
129  * connection.  The host name is cached, so it is efficient to call this
130  * several times.
131  */
132 
133 const char *
134 get_canonical_hostname(int verify_reverse_mapping)
135 {
136 	static char *canonical_host_name = NULL;
137 	static int verify_reverse_mapping_done = 0;
138 
139 	/* Check if we have previously retrieved name with same option. */
140 	if (canonical_host_name != NULL) {
141 		if (verify_reverse_mapping_done != verify_reverse_mapping)
142 			xfree(canonical_host_name);
143 		else
144 			return canonical_host_name;
145 	}
146 
147 	/* Get the real hostname if socket; otherwise return UNKNOWN. */
148 	if (packet_connection_is_on_socket())
149 		canonical_host_name = get_remote_hostname(
150 		    packet_get_connection_in(), verify_reverse_mapping);
151 	else
152 		canonical_host_name = xstrdup("UNKNOWN");
153 
154 	verify_reverse_mapping_done = verify_reverse_mapping;
155 	return canonical_host_name;
156 }
157 
158 /*
159  * Returns the remote IP-address of socket as a string.  The returned
160  * string must be freed.
161  */
162 char *
163 get_socket_address(int socket, int remote, int flags)
164 {
165 	struct sockaddr_storage addr;
166 	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
167 	socklen_t addrlen;
168 	char ntop[NI_MAXHOST];
169 	const char *result;
170 	char abuf[INET6_ADDRSTRLEN];
171 
172 	/* Get IP address of client. */
173 	addrlen = sizeof (addr);
174 	memset(&addr, 0, sizeof (addr));
175 
176 	if (remote) {
177 		if (getpeername(socket, (struct sockaddr *)&addr, &addrlen)
178 		    < 0) {
179 			debug("get_socket_ipaddr: getpeername failed: %.100s",
180 			    strerror(errno));
181 			return (NULL);
182 		}
183 	} else {
184 		if (getsockname(socket, (struct sockaddr *)&addr, &addrlen)
185 		    < 0) {
186 			debug("get_socket_ipaddr: getsockname failed: %.100s",
187 			    strerror(errno));
188 			return (NULL);
189 		}
190 	}
191 
192 	/* Get the address in ascii. */
193 	if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof (ntop),
194 	    NULL, 0, flags) != 0) {
195 		error("get_socket_ipaddr: getnameinfo %d failed", flags);
196 		return (NULL);
197 	}
198 
199 	if (addr.ss_family == AF_INET) {
200 		return (xstrdup(ntop));
201 	}
202 
203 	result = inet_ntop_native(addr.ss_family,
204 	    addr6->sin6_addr.s6_addr, abuf, sizeof (abuf));
205 
206 	return (xstrdup(result));
207 }
208 #if 0
209 static char *
210 get_socket_address(int socket, int remote, int flags)
211 {
212 	struct sockaddr_storage addr;
213 	socklen_t addrlen;
214 	char ntop[NI_MAXHOST];
215 
216 	/* Get IP address of client. */
217 	addrlen = sizeof(addr);
218 	memset(&addr, 0, sizeof(addr));
219 
220 	if (remote) {
221 		if (getpeername(socket, (struct sockaddr *)&addr, &addrlen)
222 		    < 0)
223 			return NULL;
224 	} else {
225 		if (getsockname(socket, (struct sockaddr *)&addr, &addrlen)
226 		    < 0)
227 			return NULL;
228 	}
229 	/* Get the address in ascii. */
230 	if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop),
231 	    NULL, 0, flags) != 0) {
232 		error("get_socket_ipaddr: getnameinfo %d failed", flags);
233 		return NULL;
234 	}
235 	return xstrdup(ntop);
236 }
237 #endif
238 
239 char *
240 get_peer_ipaddr(int socket)
241 {
242 	char *p;
243 
244 	if ((p = get_socket_address(socket, 1, NI_NUMERICHOST)) != NULL)
245 		return p;
246 	return xstrdup("UNKNOWN");
247 }
248 
249 char *
250 get_local_ipaddr(int socket)
251 {
252 	char *p;
253 
254 	if ((p = get_socket_address(socket, 0, NI_NUMERICHOST)) != NULL)
255 		return p;
256 	return xstrdup("UNKNOWN");
257 }
258 
259 char *
260 get_local_name(int socket)
261 {
262 	return get_socket_address(socket, 0, NI_NAMEREQD);
263 }
264 
265 /*
266  * Returns the IP-address of the remote host as a string.  The returned
267  * string must not be freed.
268  */
269 
270 const char *
271 get_remote_ipaddr(void)
272 {
273 	static char *canonical_host_ip = NULL;
274 
275 	/* Check whether we have cached the ipaddr. */
276 	if (canonical_host_ip == NULL) {
277 		if (packet_connection_is_on_socket()) {
278 			canonical_host_ip =
279 			    get_peer_ipaddr(packet_get_connection_in());
280 			if (canonical_host_ip == NULL)
281 				fatal_cleanup();
282 		} else {
283 			/* If not on socket, return UNKNOWN. */
284 			canonical_host_ip = xstrdup("UNKNOWN");
285 		}
286 	}
287 	return canonical_host_ip;
288 }
289 
290 const char *
291 get_remote_name_or_ip(u_int utmp_len, int verify_reverse_mapping)
292 {
293 	static const char *remote = "";
294 	if (utmp_len > 0)
295 		remote = get_canonical_hostname(verify_reverse_mapping);
296 	if (utmp_len == 0 || strlen(remote) > utmp_len)
297 		remote = get_remote_ipaddr();
298 	return remote;
299 }
300 
301 /* Returns the local/remote port for the socket. */
302 
303 static int
304 get_sock_port(int sock, int local)
305 {
306 	struct sockaddr_storage from;
307 	socklen_t fromlen;
308 	char strport[NI_MAXSERV];
309 
310 	/* Get IP address of client. */
311 	fromlen = sizeof(from);
312 	memset(&from, 0, sizeof(from));
313 	if (local) {
314 		if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
315 			error("getsockname failed: %.100s", strerror(errno));
316 			return 0;
317 		}
318 	} else {
319 		if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
320 			debug("getpeername failed: %.100s", strerror(errno));
321 			fatal_cleanup();
322 		}
323 	}
324 	/* Return port number. */
325 	if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
326 	    strport, sizeof(strport), NI_NUMERICSERV) != 0)
327 		fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
328 	return atoi(strport);
329 }
330 
331 /* Returns remote/local port number for the current connection. */
332 
333 static int
334 get_port(int local)
335 {
336 	/*
337 	 * If the connection is not a socket, return 65535.  This is
338 	 * intentionally chosen to be an unprivileged port number.
339 	 */
340 	if (!packet_connection_is_on_socket())
341 		return 65535;
342 
343 	/* Get socket and return the port number. */
344 	return get_sock_port(packet_get_connection_in(), local);
345 }
346 
347 int
348 get_peer_port(int sock)
349 {
350 	return get_sock_port(sock, 0);
351 }
352 
353 int
354 get_remote_port(void)
355 {
356 	return get_port(0);
357 }
358 
359 int
360 get_local_port(void)
361 {
362 	return get_port(1);
363 }
364 
365 /*
366  * Taken from inetd.c
367  * This is a wrapper function for inet_ntop(). In case the af is AF_INET6
368  * and the address pointed by src is a IPv4-mapped IPv6 address, it
369  * returns printable IPv4 address, not IPv4-mapped IPv6 address. In other cases
370  * it behaves just like inet_ntop().
371  */
372 static const char *
373 inet_ntop_native(int af, const void *src, char *dst, size_t size)
374 {
375 	struct in_addr src4;
376 	const char *result;
377 
378 	if (af == AF_INET6) {
379 		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)) {
380 			IN6_V4MAPPED_TO_INADDR((struct in6_addr *)src, &src4);
381 			result = inet_ntop(AF_INET, &src4, dst, size);
382 		} else {
383 			result = inet_ntop(AF_INET6, src, dst, size);
384 		}
385 	} else {
386 		result = inet_ntop(af, src, dst, size);
387 	}
388 
389 	return (result);
390 }
391